WWDC Quick Look 💓 By SwiftGGTeam
Migrate to SwiftData

Migrate to SwiftData

观看原视频

Highlight

SwiftData 可以和 Core Data 共存于同一个应用,开发者既可以用 Xcode 助手一键生成 SwiftData 模型类完成完全迁移,也可以让两个持久化栈共享同一个存储文件实现渐进式过渡,无需一次性重写所有代码。

核心内容

很多应用已经用 Core Data 跑了多年,数据模型复杂、代码量庞大。WWDC23 推出 SwiftData 后,这些应用的开发者面临一个实际问题:要不要迁移?怎么迁移?

这个 session 给出了三种方案:完全迁移、共存模式、以及从 Xcode 自动生成模型类的快捷入口。核心思路是灵活——根据你的团队资源、版本兼容需求、代码复杂度来选择最适合的路径。

自动生成 SwiftData 模型类

01:05)如果你已有 Core Data 的 .xcdatamodeld 文件,Xcode 可以帮你自动生成对应的 SwiftData 模型类。

操作步骤:

  1. 在 Xcode 中选中模型文件
  2. 菜单栏选择 Editor > Create SwiftData Code
  3. 为每个实体生成对应的 Swift 文件

生成的 SwiftData 模型长这样:

import SwiftData

@Model
class Trip {
    var name: String
    var destination: String
    var startDate: Date
    var endDate: Date
    var livingAccommodation: LivingAccommodation?
    var bucketList: [BucketListItem]?
}

关键点:

  • 生成的类自动加上 @Model
  • 属性和关系与 Core Data 实体一一对应
  • 如果从头新建 SwiftData 应用,不需要这个助手,直接写 @Model 类即可

完全迁移

03:09)完全迁移意味着删除 Core Data 的所有痕迹,用 SwiftData 替代。

迁移前的检查清单:

  • 每个 Core Data 实体必须有对应的 SwiftData 模型类
  • 实体名称必须完全匹配
  • 所有属性和关系必须在 SwiftData 中都有对应定义
  • 确认所有 Core Data 特性在 SwiftData 中都受支持

迁移步骤:

  1. 用 Xcode 助手生成 SwiftData 模型类
  2. 删除 .xcdatamodeld 文件
  3. 删除原来的 Persistence 文件(设置 Core Data stack 的代码)
  4. .modelContainer() 设置 SwiftData stack

04:37)SwiftUI 中设置 ModelContainer:

@main
struct TripsApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .modelContainer(
            for: [Trip.self, BucketListItem.self, LivingAccommodation.self]
        )
    }
}

关键点:

  • .modelContainer() 同时创建 container 和 context
  • Context 自动注入到 SwiftUI 环境中
  • 不需要手动管理 NSPersistentContainer

04:57)对象创建的对比:

Core Data 方式:

@Environment(\.managedObjectContext) private var viewContext

let newTrip = Trip(context: viewContext)
newTrip.name = name
newTrip.destination = destination
newTrip.startDate = startDate
newTrip.endDate = endDate

SwiftData 方式:

@Environment(\.modelContext) private var modelContext

let trip = Trip(
    name: name,
    destination: destination,
    startDate: startDate,
    endDate: endDate
)

modelContext.insert(object: trip)

关键点:

  • SwiftData 用普通初始化器创建对象,不需要传 context
  • 创建后调用 insert() 标记为需要持久化
  • 代码更简洁,类型更安全

05:51)保存机制也有变化。SwiftData 支持隐式保存:

  • UI 生命周期事件触发保存
  • Context 变更后定时自动保存
  • 可以移除 Core Data 中显式调用 save() 的代码

06:16)数据获取从 FetchRequest 变为 @Query

@Query(sort: \.startDate, order: .forward)
var trips: [Trip]

关键点:

  • @Query 直接返回 [Trip],不需要包装成 FetchedResults
  • 支持排序和 predicate
  • 自动响应数据变化刷新 UI

共存模式

06:51)完全迁移不总是可行。如果你的应用需要支持 iOS 16 及以下版本,或者代码量太大无法一次性重写,共存模式是更好的选择。

共存模式让 Core Data 和 SwiftData 两个独立的持久化栈指向同一个存储文件。你可以在旧代码中继续用 Core Data,在新功能中使用 SwiftData。

07:30)设置共存的关键配置:

let url = URL(fileURLWithPath: "/path/to/Trips.store")

if let description = container.persistentStoreDescriptions.first {
    description.url = url
    description.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
}

关键点:

  • 两个 stack 必须指向同一个存储 URL
  • 必须开启 Persistent History Tracking
  • SwiftData 自动开启此功能,Core Data 需要手动设置
  • 如果不开启,存储会被设为只读模式

08:51)类名冲突的处理:

// Core Data 类
class CDTrip: NSManagedObject {
    // ...
}

// SwiftData 类
@Model final class Trip {
    // ...
}

关键点:

  • Core Data 和 SwiftData 的类不能同名
  • 可以给 Core Data 类加前缀(如 CDTrip)
  • 类名改了,但实体名保持不变
  • 也可以在 Managed Object Model Editor 中修改类名

共存模式的其他要求:

  • 两个 schema 必须保持同步,不能分叉
  • 新增属性和关系必须以相同方式添加到两个模型中
  • 实体版本哈希必须匹配,否则会触发意外迁移
  • 多版本 schema 需要正确管理版本差异

UIKit / AppKit 应用怎么办

10:25)SwiftData 虽然和 SwiftUI 深度集成,但 UIKit 和 AppKit 应用也能用:

  • 共存方案:UIKit 代码继续绑定 Core Data,SwiftData 在并行的新功能中使用
  • 包装方案:把 SwiftData 类当作普通 Swift 类,用 UIKit 代码包装使用

详细内容

迁移决策树

选择哪种迁移策略,取决于几个因素:

因素完全迁移共存模式
最低支持版本iOS 17+iOS 16 或更早
代码重写成本高(一次性)低(渐进式)
团队资源充足有限
数据模型复杂度简单到中等复杂
长期维护更简洁需要维护两套代码

Schema 兼容性检查

迁移前必须验证:

  1. 实体名称:Core Data 实体名 == SwiftData 类名
  2. 属性名称和类型:完全匹配
  3. 关系:双向关系在 SwiftData 中用 @Relationship 标注
  4. 约束:如唯一性约束用 @Attribute(.unique)
  5. 不受支持的特性:如 fetched properties、fetch requests 等

版本管理

共存模式下,schema 变更需要同时更新两个模型:

  1. 在 Core Data 的 .xcdatamodeld 中添加新属性
  2. 在 SwiftData 的 @Model 类中添加对应属性
  3. 确保两个模型的实体版本哈希一致
  4. 使用 versioned schema 管理 SwiftData 模型版本

核心启发

1. 给现有 Core Data 应用逐步引入 SwiftData

  • 做什么:不改动旧功能,在新模块中使用 SwiftData,通过共存模式共享数据
  • 为什么值得做:零风险尝试 SwiftData,团队可以边学边用,不需要大规模重构
  • 怎么开始:配置共存 stack,给 Core Data 类加前缀避免命名冲突,在新功能中使用 @Query@Model

2. 用 Xcode 助手快速生成 SwiftData 模型

  • 做什么:几分钟内把现有的 .xcdatamodeld 转换成 SwiftData 类
  • 为什么值得做:避免手写映射错误,自动保持属性名和类型一致
  • 怎么开始:选中模型文件 > Editor > Create SwiftData Code,检查生成的类是否符合预期

3. 做一个跨版本的笔记应用

  • 做什么:支持 iOS 16 和 iOS 17+ 的笔记应用,iOS 16 用 Core Data,iOS 17 用 SwiftData
  • 为什么值得做:共存模式让同一个存储文件被两个 stack 访问,用户数据无缝过渡
  • 怎么开始:运行时判断系统版本,选择初始化 Core Data stack 或 SwiftData stack,共享同一个存储 URL

4. 重构遗留的 Core Data 代码

  • 做什么:把臃肿的 Core Data 代码逐步替换成 SwiftData
  • 为什么值得做:减少样板代码,获得类型安全和更好的 SwiftUI 集成
  • 怎么开始:从最简单的实体开始迁移,验证数据一致性后逐步扩大范围,用 @Query 替换 FetchRequest

关联 Session

评论

GitHub Issues · utterances