大多数浏览器和
Developer App 均支持流媒体播放。
-
Core Data 模式进化
了解如何在您的 App 更新后简单便捷地迁移 Core Data 模式,并轻松完成对数据模型的变更。我们将向您介绍如何利用内置的迁移工具,让您的数据存储保持最新状态,并允许 Core Data 分析您的模式,对数据模型迁移进行推断。我们还将提供最佳实践,帮助您克服艰难的迁移挑战,并探索 Core Data 模式如何与 CloudKit 交互来支持在云中的轻松迁移。为能更好地理解此讲座,我们建议您先熟悉 Core Data 模式和数据类型,并对 Core Data 数据库和 CloudKit 之间的同步有一些基本的了解。
资源
相关视频
WWDC23
WWDC22
-
下载
♪ ♪
David Stites: 嗨 欢迎来到 发展您的 Core Data 架构 我叫 David Stites 是 Core Data 团队的一名工程师 在本期讲座中 我很高兴与您讨论 如何在您的 App 中更新和迁移 Core Data 架构 本期讲座的议程是 了解什么是架构迁移 为什么您的 App 必须在更新 其数据模型后执行架构迁移 如何迁移现有架构 以及 CloudKit 和架构迁移如何交互 首先 什么是架构迁移 以及为什么在更新数据模型时 App 必须迁移
由于涉及到 App 可能有必要更改您的数据模型 更新数据模型需要在底层存储架构中 具体化这些更改 考虑一下这个数据模型 这有一个 Aircraft 实体 它有两个属性 即类型和发动机数量 这些属性反映在底层存储中 如果我添加了“乘客数量”属性 那我需要添加相应的存储 迁移后 更改完全反映在底层存储中 如果不迁移底层存储中的更改 Core Data 将拒绝打开您的持久存储 因为新更改的模型 与用于存储的模型不匹配 试图打开不兼容的存储将导致代码 NSPersistentStore- IncompatibleVersionHashError出错 如果您收到此错误 这应该是在指示您 需要进行迁移 现在我已经解释了什么是架构迁移 以及为什么它对开发 App 至关重要 让我来告诉您迁移是如何完成的 Core Data 具有内置的数据迁移工具 可帮助您的 App 进行数据存储 使其与当前数据模型保持同步 这些工具统称为“轻量级迁移”
轻量级迁移是首选的迁移方法 轻量级迁移从源 和目标托管对象模型之间的 差异自动分析和推断迁移 在运行时 Core Data 在 NSBundle 类的 .allBundles 和 .allFrameworks 方法 返回的包中查找模型 然后轻量级迁移 会生成一个映射模型 将您在 App 中所做的更改 具体化到您的数据库架构中
使用轻量级迁移需要 对数据模型进行更改 以适应明显的迁移架构
涉及属性的轻量级操作 包括添加属性 移除属性 将非可选属性变为可选 将可选属性变为非可选 并定义默认值 以及重命名属性 如果您想要重命名属性 请将目标模型中的 重命名标识符 设置为源模型中相应属性的名称
重命名标识符位于 Xcode 数据模型编辑器的 属性检查器中 例如 您可以将 Aircraft 实体的颜色属性 重命名为 paintColor 重命名标识符要创建一个规范名称 因此将重命名标识符 设置为源模型中属性的名称 除非该属性已经具有重命名标识符 这意味着您可以在模型的 版本 2 中重命名一个属性 然后在版本 3 中再次重命名它 重命名将从版本 2 到版本 3 或者从版本 1 到版本 3 正确工作
轻量级迁移还可以毫不费力地 处理关系的变化 您可以添加新关系或删除现有关系 您还可以通过使用重命名标识符 来重命名关系 就跟属性一样 此外 您还可以更改关系基数 例如 从一对一迁移到一对多 或者从无序的一对多 迁移到有序的一对多 反之亦然
如果您猜测实体也有资格 进行轻量级迁移 那么您是对的 您可以添加新实体 删除现有实体 以及重命名实体 您还可以创建新的父实体或子实体 并在实体层次结构中上下移动属性 您可以将实体移入或移出层次结构 但是不能合并实体层次结构 如果两个现有实体 在源中不共享公共父级 则它们无法在目标中共享公共父级 轻量级迁移由两个选项键控制 NSMigratePersistent- StoresAutomaticallyOption 和 NSInferMappingModelAutomaticallyOption 将存储添加到持久性协调器时 如果检测到持久性存储 不再匹配当前模型 这两个将值设置为真的键的存在 将导致核心数据自动执行轻量级迁移 如果您使用 NSPersistentContainer 或 NSPersistentStoreDescription 这些选项会自动为您设置 您无需执行任何操作 如果您使用的是替代 API 例如 .NSPersistentStoreCoordinator .addPersistentStore (type:configuration:at:options:) 可以通过设置和传递带有能够将 NSMigratePersistent-StoresAutomaticallyOption 和 NSInferMappingModelAutomaticallyOption 的值 设置为 YES 的键的 选项字典 NSMigratePersistent-StoresAutomaticallyOption 来请求轻量级迁移 如果 Core Data 检测到持久存储 不再匹配当前模型 它将自动执行轻量级迁移
以下是它在代码中的工作方式 首先我将导入 CoreData 并创建一个托管对象模型 然后我将使用刚刚创建的模型 创建一个持久存储协调器 请注意我创建的选项字典 当我将存储添加到持久协调器时 我将传递这个字典 最后 我将把存储添加到协调器中 如果需要 迁移将自动进行 不管您使用什么 API 对数据模型的更改都可以直接 在 App 附带的同一个模型中进行 无需创建模型的新版本即可进行更改 如果您想提前确定 Core Data 是否可以推断 源模型和目标模型之间的映射模型 而不需要实际进行迁移工作 那么可以使用 NSMappingModel.inferredMappingModel 方法 如果 Core Data 能够创建推断模型 则该方法将返回该模型 否则 它将返回 nil
有时 对模式的组合更改 可能会超出轻量级迁移的能力 我将向您描述如何处理该问题 并仍然使用轻量级迁移 回到我们之前的示例模型 假设我们之前添加了 一个名为 flightData 的属性 该属性 使用外部存储来存储二进制数据 由存储在 FLIGHT_DATA 中的 文件路径来指示 此外 假设需要更改该属性 以在内部存储数据并删除外部存储 检查此迁移是否符合 轻量级迁移的任何功能 然后发现它不符合 从表面上看 我们似乎陷入了困境 无法进行此更改 但是不要害怕 轻量级迁移仍可用于执行更复杂 且不一致的迁移 尽管需要多个步骤
目标是将不符合轻量级迁移条件的 迁移任务分解为 符合轻量级迁移条件的最小迁移系列 通常 如果原始模型为 A 目标模型为 B 但模型 B 的变更不符合 轻量级迁移的条件 则可以通过引入一个或多个 分解这些变更的模型版本来创建桥梁
每一个引入的模型 都将具有一个或多个操作 这些操作在组成不一致变更的 能力范围之内 这导致了一系列的迁移 其中每个模型现在是轻量级可迁移的 但是等同于不一致的迁移 回到不适合轻量级迁移的 示例 我们的原始模型是模型 A 我将通过引入新模型版本 A' 来开始分解任务 并添加一个新属性 tmpStorage 该属性将临时用于存储 从外部文件导入的数据
接下来我将 把数据从外部文件导入到 我们的新属性中 导入此数据的代码 与 Core Data 提供的功能是分开的 该导入的执行介于两次迁移之间 安全导入数据后 我将从 A' 创建 另一个新版本的模型 A'' 在 A'' 中 我将删除旧的外部存储属性 同时重命名新属性 我描述的每个步骤 都在轻量级迁移的能力范围内 直观地说 可以构建一个事件循环 使用轻量级迁移选项集打开持久存储 并以串行顺序迭代地 遍历每个未处理的模型 Core Data 将迁移存储 如果您在迁移期间 执行特定于 App 的逻辑 例如在上一个示例中 我是如何从外部文件导入数据的 那么在迁移因进程终止 而中断的情况下 该逻辑必须是可重启的 如果您的 App 使用 Core Data 和 CloudKit 那么在使用 Core Data 设计数据模型时 您应该牢记一些要点 要在 Core Data 存储和 CloudKit 数据库之间传递记录 它们需要对数据模型有共同的理解 您可以在 Core Data 模型编辑器中 定义此模型 该模型随后用于生成 CloudKit 架构 生成的架构最初 是在开发环境中创建的 然后升级到生产环境 您应该意识到了 CloudKit 并不支持 Core Data 模型的 所有功能 设计模型时 请注意以下限制 并创建兼容的数据模型 例如 不支持对实体的唯一约束 不支持将 undefined 和 objectID 属性类型作为其属性类型 并且关系必须是可选的 并且具有反向关系 此外 CloudKit 不支持拒绝删除规则 在开发 App 时 您将使用开发环境 CloudKit 架构可以在此环境中 自由修改 但是 将架构升级到生产模式后 记录类型及其字段是不可变的 虽然轻量级迁移 可以处理许多不同的场景 但 CloudKit 在它支持的内容上 受到更多限制 我之前描述的许多轻量级操作 都不受支持 具体来说 CloudKit 支持 向现有记录类型添加新字段 和添加新记录类型 您不能修改或删除 现有的记录类型或字段 修改模型架构时 请考虑这些限制
当需要更新数据模型时 请记住轻量级迁移 仅在本地存储文件中实现 架构更改 无论 CloudKit 是否使用特定存储 迁移只会更改磁盘上的存储 而不会更改 CloudKit 架构 您仍然需要通过运行架构初始化程序 在开发数据库中使这些更改具体化 然后使用 CloudKit 控制台 将开发中的这些更改提升到生产中 请记住 您的 App 用户 将同时使用旧版本 和新版本 最新版 App 当然会知道 架构中所有新添加的功能 旧版 App 不会知道 新字段或记录类型
由于 CloudKit 架构本质上是附加的 因此请考虑将架构迁移到 运行旧版 App 设备上的影响 例如 一个常见的缺陷是 忘记更新旧版 App 从而使用新版本已不使用的旧字段 下面是一些 迁移 CloudKit 架构的策略 第一种选择是以增量方式 向现有记录类型添加新字段 如果您采用这种方法 旧版 App 将可以访问 用户创建的每条记录 但不能访问每个字段
第二个选项是通过包含版本属性 来对实体进行版本设置 然后使用提取请求 仅选择与 App 当前版本兼容的记录 如果您采用这种方法 旧版 App 将无法获取 用户使用较新版本创建的记录 从而有效地将它们隐藏在该设备上 最后一个策略是使用 NSPersistentCloudKitContainerOptions 创建一个全新的容器 将新的存储与新的容器相关联 请注意 如果用户有一个大型数据集 将数据集上传到 iCloud 可能需要很长时间 无论您使用哪种方法 都要小心设计您的数据模型 一定要考虑跨版本的兼容性问题 并一起测试不同版本的数据模型 既然我们已经彻底讨论了数据模型 迁移和 CloudKit 那么我来实际演示一下 您可能已经猜到了 我是一名飞行员 我创建了一个小 App 来记录我的飞行时间 这是该 App 的数据模型 我有一个名为 LogEntry 的实体 并添加了许多属性 例如飞机类型 飞行时间 始发地 目的地和尾号 可以让我记录需要的体验信息 当我第一次运行这个 App 时 Core Data 将创建存储 并在该存储中实现架构 在运行 App 之前 我将打开 com.Apple.CoreData.SQLDebug 和 com.apple.CoreData.MigrationDebug 环境变量 这会使 Core Data 记录 它正在执行的步骤 有了这些参数 我将运行该 App
随着 App 启动 Core Data 在记录它正在执行的步骤 创建文件 为存储创建元数据 以及实现架构 SQLite 使用我们的架构创建了 表 ZLOGENTRY 这也可以通过使用 sqlite3 命令行工具 查看存储文件来确认 在这里 我有一个 LogEntry 表 它有与我在 数据模型中创建的属性对应的列 现在我要做一些轻量级的改动
我正在添加一些新的实体 Aircraft Pilot 和 Airport 这会帮助我规范化架构 我正在将 LogEntry 实体中的 一些属性更改为关系 例如 目的地和始发地 从字符串属性转变为 机场一对一关系 Airport 实体还有两个新属性 即 icaoIdentifier 和 faaIdentifier type 属性被提升为 一个新实体 Aircraft 我添加了两个新属性 tailNumber 和 registrationNumber 在 LogEntry 上 我正在从 LogEntry 创建与飞机的一对一关系
最后 我添加了一个具有名称 和证书 ID 的 Pilot 实体
每个日志条目 将与一个 Pilot 实体相关 现在我已经完成了对数据模型的更改 我将再次运行该 App
噢 我在运行 App 时收到一个错误 检查一下代码 是 NSPersistentStore- IncompatibleVersionHashError 该错误意味着我当前模型的架构 不再与存储中的模型 相匹配 我需要迁移存储架构 我可以通过以下三种方式中的一种 来做到这一点 使用第一种方法 我可以将我的代码 转换为使用 NSPersistentContainer 因为轻量级迁移选项会自动为我设置 第二种方法 我可以使用 NSPersistentStoreDescription 因为轻量级迁移选项 也会自动为我设置 最后 使用第三种方法 我可以 在选项字典上 手动设置轻量级迁移选项 并在打开存储时 将该字典传递给协调器 我想我会选择第一个选项 使用 NSPersistentContainer 现在我已将代码转换为使用 NSPersistentContainer 我将启动 App 并再次观察到 Core Data 正在迁移 存储文件中的架构
同样这可以使用 sqlite3 命令行工具来确认 请注意 Core Data 使用轻量级迁移 自动实现了新架构 还有什么比这更容易呢 在结束演示之前 我想展示第 3 个选项 回想一下 在此选项中 我在选项字典上手动设置 轻量级迁移选项 然后在打开存储时 将该字典传递给协调器 最终结果是相同的 因为存储迁移到了新架构 当对数据模型进行更改时 请使用轻量级迁移来帮助您 对于绝大多数数据模型更改来说 轻量级迁移非常灵活且易于使用 如果您有更复杂的数据模型 请将该模型分解成 由轻量级变化组成的模型 最后如果您在 App 中使用 CloudKit 请仔细考虑数据模型更改的影响 彻底测试所有数据模型更改 我希望您会发现这些信息很有用 并且会考虑更新项目中的模型 来构建一些很棒的新功能 感谢您与我一起飞行 祝您的 WWDC 之旅一切顺利
-
-
6:16 - Migrate your Core Data schema
import CoreData let storeURL = NSURL.fileURL(withPath: "/path/to/store") let momURL = NSURL.fileURL(withPath: "/path/to/model") guard let mom = NSManagedObjectModel(contentsOf: momURL) else { fatalError("Error initializing managed object model for URL: \(momURL)") } let coordinator = NSPersistentStoreCoordinator(managedObjectModel: mom) do { let opts = [NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption: true] try coordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: Optional<String>.none, at: storeURL, options: opts) } catch { fatalError("Error configuring persistent store: \(error)") }
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。