Migrate to SwiftData
Swift & UI 进阶 20m

迁移到 SwiftData

Migrate to SwiftData

2023年6月5日

在 Apple 官方观看视频

一句话判断

Core Data 到 SwiftData 的迁移有两条路径——完全迁移(删掉 Core Data 栈,全面拥抱 SwiftData)和共存模式(两个栈共享同一个持久化存储,渐进式迁移),Xcode 的 Managed Object Model Editor 助手可以自动生成 SwiftData 模型类。

这场 Session 讲了什么

Luvena 详细介绍了从 Core Data 迁移到 SwiftData 的三种场景。

自动生成 SwiftData 模型类:使用 Xcode 的 Managed Object Model Editor 助手(Editor > Create SwiftData Code),可以从现有的 Core Data 模型文件自动生成对应的 SwiftData 模型类。生成的类包含实体属性和关系的完整映射。

完全迁移:删除 Core Data 的 Managed Object Model 文件和 Persistence 文件,替换为 SwiftData 的 ModelContainer 和 @Query。关键约束是 SwiftData 模型中实体名称和属性必须与 Core Data 中的完全匹配,这样才能正确读取现有数据。SwiftData 的隐式保存机制替代了 Core Data 的手动 save 调用。

共存模式:Core Data 和 SwiftData 使用两个完全独立的持久化栈,但指向同一个存储文件。这允许渐进式迁移——不需要一次性重写所有代码。前提条件是必须开启持久化历史追踪(Persistent History Tracking),否则存储会被设为只读模式。SwiftData 自动开启此功能,但 Core Data 需要手动配置。

值得深挖的点

Schema 匹配的严格性:完全迁移时,SwiftData 模型的实体名称和属性名必须与 Core Data 中的完全一致。任何不匹配都会导致数据无法正确读取。迁移前需要彻底测试所有模型。

共存模式的双栈设计:两个栈完全独立运行,通过同一个 SQLite 文件通信。Persistent History Tracking 是关键的同步机制——它记录所有变更历史,让另一个栈能感知到对方做的修改。

隐式保存的工作时机:SwiftData 在 UI 生命周期事件和定时器触发时自动保存。你不再需要手动调用 save(),但你仍然可以显式调用 modelContext.save() 来强制保存。

向后兼容的考虑:SwiftData 仅支持 iOS 17+ 和 macOS Sonoma+。如果你的应用还需要支持旧系统,共存模式是唯一选择——在旧系统上用 Core Data,在新系统上用 SwiftData。

代码片段

// 完全迁移 - 设置 SwiftData 栈
@main
struct SampleTripsApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        // 替代 Core Data 的 NSPersistentContainer
        .modelContainer(for: [Trip.self, LivingAccommodation.self, BucketListItem.self])
    }
}
// 完全迁移 - 对象创建的对比
// Core Data 方式
let trip = Trip(context: managedObjectContext)
trip.name = "Paris"
trip.destination = "France"
try managedObjectContext.save()  // 手动保存

// SwiftData 方式 - 更简洁
let trip = Trip(name: "Paris", destination: "France")
modelContext.insert(trip)
// 不需要手动 save() - 隐式保存自动处理
// 完全迁移 - 数据查询的对比
// Core Data 方式
@FetchRequest(
    sortDescriptors: [NSSortDescriptor(keyPath: \Trip.startDate, ascending: true)]
)
var trips: FetchedResults<Trip>

// SwiftData 方式
@Query(sort: \Trip.startDate, order: .forward)
var trips: [Trip]
// 共存模式 - 配置 Core Data 栈指向同一存储
let storeURL = URL.storeURL(for: "MyApp", databaseName: "SharedStore")
let description = NSPersistentStoreDescription(url: storeURL)
// 必须开启持久化历史追踪
description.setOption(true as NSNumber,
    forKey: NSPersistentHistoryTrackingKey)
container.persistentStoreDescriptions = [description]

最佳实践

  • 用 Xcode 助手生成模型类:不要手写迁移代码,用 Editor > Create SwiftData Code 自动生成,确保属性映射正确。
  • 完全迁移前彻底测试 Schema 匹配:每个实体的名称和属性都必须精确匹配,遗漏一个就会导致数据丢失。
  • 共存模式必须开启 Persistent History Tracking:否则存储进入只读模式,两个栈都无法写入。
  • 共存模式适合渐进式迁移:先在新功能中使用 SwiftData,旧代码继续用 Core Data,逐步替换。
  • 考虑最低支持版本:如果需要支持 iOS 16 及更早版本,只能用共存模式。

还有什么值得关注

  • 共存模式为大型应用提供了现实的迁移路径——不需要一次性重写所有数据层代码。
  • SwiftData 的隐式保存大幅减少了样板代码,但也意味着你需要信任系统的保存时机。
  • Session 中的 SampleTrips 应用是一个很好的参考项目,展示了 Trip、LivingAccommodation 和 BucketListItem 三个实体之间的完整关系映射。
WWDC 2023