数据迁移实战
问题
App 更新后数据库 Schema 变了,如何安全迁移?
答案
Core Data 迁移
// 1. 轻量级迁移(推荐,自动处理简单变更)
let description = NSPersistentStoreDescription()
description.shouldMigrateStoreAutomatically = true
description.shouldInferMappingModelAutomatically = true
// 支持的变更:
// - 新增属性(有默认值)
// - 删除属性
// - 重命名属性(需设置 Renaming ID)
// - 新增 Entity
复杂迁移
// 2. 自定义迁移(需要数据转换时)
// 创建 Mapping Model (.xcmappingmodel)
class UserMigrationPolicy: NSEntityMigrationPolicy {
override func createDestinationInstances(
forSource sInstance: NSManagedObject,
in mapping: NSEntityMapping,
manager: NSMigrationManager
) throws {
let dest = NSEntityDescription.insertNewObject(
forEntityName: "User",
into: manager.destinationContext
)
// 数据转换:将 fullName 拆为 firstName + lastName
let fullName = sInstance.value(forKey: "fullName") as? String ?? ""
let parts = fullName.split(separator: " ")
dest.setValue(String(parts.first ?? ""), forKey: "firstName")
dest.setValue(String(parts.last ?? ""), forKey: "lastName")
}
}
SwiftData 迁移
// SwiftData 使用 VersionedSchema
enum SchemaV1: VersionedSchema {
static var versionIdentifier: Schema.Version = .init(1, 0, 0)
static var models: [any PersistentModel.Type] = [UserV1.self]
}
enum SchemaV2: VersionedSchema {
static var versionIdentifier: Schema.Version = .init(2, 0, 0)
static var models: [any PersistentModel.Type] = [UserV2.self]
}
let plan = SchemaMigrationPlan(schemas: [SchemaV1.self, SchemaV2.self])
安全策略
| 策略 | 说明 |
|---|---|
| 备份 | 迁移前备份数据库文件 |
| 灰度 | 新版本先小范围验证 |
| 回退 | 迁移失败时恢复备份 |
| 测试 | 用旧版本数据库文件跑迁移单元测试 |
常见面试问题
Q1: 轻量级迁移失败怎么办?
答案:如果 Schema 变更超出轻量级迁移能力(如属性类型改变),需要创建 Mapping Model 自定义迁移逻辑。或者分两步:v1 → v1.5(兼容中间版本)→ v2。