SwiftData ModelContainer迁移:将LocalMovie整合至Child模型实现无感知迁移
SwiftData 无感知迁移 LocalMovie 至 Child.movies 方案
核心思路
通过模型版本化 + 自定义迁移操作实现无感知迁移,分阶段完成模型结构兼容与数据关联,全程无需用户干预。
步骤1:定义版本化模型与新模型
先为现有模型标记版本,同时新增关联目标Child模型:
原有LocalMovie模型(标记初始版本)
@Model @ModelVersion("1.0") final class LocalMovie { var id: UUID var title: String // 其他原有属性 init(id: UUID, title: String) { self.id = id self.title = title } }
新增Child模型(关联LocalMovie集合)
@Model final class Child { var id: UUID @Relationship(deleteRule: .cascade) var movies: [LocalMovie] init(id: UUID, movies: [LocalMovie] = []) { self.id = id self.movies = movies } }
步骤2:配置自定义迁移逻辑
在初始化ModelContainer时,指定迁移计划,自动完成数据关联:
func setupModelContainer() throws -> ModelContainer { let schema = Schema([LocalMovie.self, Child.self]) let config = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false) // 定义从版本1.0到2.0的迁移规则 let migrationPlan = MigrationPlan( fromVersion: "1.0", toVersion: "2.0" ) { context in // 1. 创建业务所需的Child实例(示例为单例,可根据业务调整为多实例) let targetChild = Child(id: UUID()) context.insert(targetChild) // 2. 批量读取所有LocalMovie数据 let movieFetch = FetchDescriptor<LocalMovie>() guard let allMovies = try? context.fetch(movieFetch) else { return } // 3. 关联所有LocalMovie到Child的movies属性 targetChild.movies.append(contentsOf: allMovies) // 4. 提交迁移数据 try? context.save() } // 初始化容器并应用迁移计划 return try ModelContainer(for: schema, configurations: config, migrationPlan: migrationPlan) }
步骤3:优化无感知体验细节
- 后台执行迁移:避免大数据量迁移阻塞UI,将容器初始化放在后台队列:
DispatchQueue.global(qos: .background).async { do { let container = try setupModelContainer() // 迁移完成后通知主线程更新UI或业务逻辑 DispatchQueue.main.async { // 处理容器就绪后的操作 } } catch { // 迁移失败兜底逻辑(如 fallback 到内存容器) } } - 数据校验:迁移完成后新增校验逻辑,确保数据完整性:
func verifyMigration(context: ModelContext) throws { let totalMovies = try context.fetchCount(FetchDescriptor<LocalMovie>()) guard let child = try context.fetch(FetchDescriptor<Child>()).first else { throw MigrationError.missingChildInstance } guard child.movies.count == totalMovies else { throw MigrationError.incompleteAssociation } } enum MigrationError: Error { case missingChildInstance case incompleteAssociation }
备选风险降级方案
如果担心单次迁移风险,可分两步发布:
- 第一版仅新增
Child模型,不做数据关联,让用户完成模型结构升级。 - 第二版在App启动时执行后台数据关联逻辑,完成最终迁移。
这种方式适合数据量极大的场景,降低单次迁移失败影响范围。
内容的提问来源于stack exchange,提问作者eltintin
相关产品推荐
相关产品推荐

