大多数浏览器和
Developer App 均支持流媒体播放。
-
将 Core Data 与 CloudKit 搭配使用
CloudKit 提供了强大的云同步技术,而 Core Data 提供了大量的数据建模和持久性 API。了解如何结合利用这些互补的技术来轻松构建基于云的 app。了解如何利用新的 Core Data API 轻松管理您整个 app 内的数据流以及 CloudKit 的进出数据流。加入我们,进一步了解如何结合使用这些框架来在您客户的所有设备上提供出色的体验。
资源
相关视频
WWDC22
WWDC20
WWDC19
-
下载
早上好 我是 Nick Gillett 一名 Apple Core Data 团队的工程师 欢迎大家来到 Using Core Data with CloudKit 会议 今天 我们要谈的是 这样的一种想法 我们想要数据随时可用 不论我使用什么设备 也不论我身处何方 如果想要实现这种设想 我们需要让 添加该功能到你的 App 上这个步骤 变得更加方便 我相信今天在座的各位 大多数都携带了 iPhone 也许在家还有一台 Mac 而此时此刻你的背包里 或许还有一台 MacBook 或者 MacBook Pro 我们在这些设备上 操作的所有数据 都存储在本地上 对吧 对于我们来说 不用任何交互 把数据从一个设备上 转移到另外一个设备 还是比较麻烦的 现在为了解决这个问题 我们想到了云存储 因为它可以让我们 把一个设备上的数据 无缝透明地 转移到我们所拥有的 其他设备上 即使我们只有一台设备 云存储也是非常好用的 对吧 当 App 在设备上产生数据 它在云端备份并存储 所以当我们主动或碰巧 使用一台新的设备 别问我是怎么知道的 在踏出商店之后 这台新设备就能变成 我们熟悉和深爱的那个 这也许会让你感到惊讶 现在我们平台上 已经有一些技术 可以帮助我们解决这个问题 例如 Core Data 提供了 一套健壮的 API 在 App 和磁盘上 管理本地数据 而 CloudKit 框架可以访问 世界上最大的 分布式数据库之一 这两个框架在 Apple 的所有平台上均可用 正因如此 我们才能 创作出各种各样的 App 事实上 这些框架 其实很相似 它们甚至用同一套模式和范例 来根据对象 模型和存储 对它们的 API 进行建模 在 Core Data 我们把对象实例 叫做 NSManagedObject 它们可以让我们的 App 访问存储在磁盘上的值 相似的 CloudKit 利用 类似键值对的 CKRecord 来实现 可以访问你存储在 云端的数据 这些对象 是用模型来描述的 在 Core Data 我们把它叫做 NSManagedObjectModel 你可以使用代码 或者是 Xcode 模型编辑器创作出来 非常相似 CloudKit 使用的是 Schema CloudKit Schema 可以在你使用 CKRecords 开发时 由 CloudKit 动态定义 或者使用 CloudKit 仪表盘定义 最终 使用 Core Data 将对象持久化 这也是我们称作的存储 在 Core Data 中叫做 NSPersistentStore 实例 但是在 CloudKit 里 CKRecords 是储存在 CKRecordZone 或者 CKDatabase 中的 正如你们所见 当然很多人也曾经 向我指出 如果我们可以 把两个相似机制的框架 结合的过程变得简单 那就再好不过了 为了给你们展示 我们这些年的成果 我将带领你们看一下 在 Xcode 中 制作一款新 App 是什么感受 大家请看 我打开 Xcode 我要制作一款 Master-Detail App 模版的 iOS 项目 我喜欢 Master-Detail App 是因为它给我们 提供了很棒的 UI 可以在探索 Core Data 功能时使用 所以我选择它 然后点按 Next 给我的 App 命名 此情此景 就叫 WWDC Demo 吧 然后 因为我们是来了解 Core Data 我们需要打开它的复选框 在 Xcode 11 里面 它叫做 Use CloudKit 这一步是告诉 Xcode 我们想要制作一款 App 而它需要同时用到 Core Data 和 CloudKit 那么让我们选中 然后我们点按 Next 设置 App 在文件系统中的存储位置
当我们点按 Create Xcode 就为我们生成了 App 如果你之前已经构建过 使用 CloudKit 的 App 那么你就知道 在它准备构建运行之前 我们还需要 添加一些其他的东西 这些额外的功能要在 Signing & Capabilities 标签中添加 我们需要加上这两个 第一个是 iCloud 功能 所以我点按 Capability 旁边的 + 号 输入 iCloud 然后点按回车键 当我做这一步的时候 我可以打开 CloudKit 的复选框 你可以看到它还给我 添加了 Push Notifications 复选框 Xcode 也能自动
下面 我们要添加后台模式功能 为了添加功能 再次点击 + 号 输入 Background 再点按回车键 我们这么做的原因是 启用远程通知 这样就可以使我们的 App 在非运行状态 接收推送通知 那么 让我们运行这个 App 看看效果如何
现在你可以看到 我们已经有了一个很简单的 App 有两个视图控制器 左侧是表格视图 右侧是详情视图控制器 现在我为 App 添加数据 点按右上角的 + 号 默认状态下 Xcode 会生成 一个简单的 Core Data 模型 仅仅是一个时间戳 但是 我们可以看到 同步功能是如何运行的 这样我们就需要另外一个设备 现在在我们的 iPhone 上面运行这个 App 你们可以看到 我们已经 有了主视图控制器 以及我们在 iPad 上添加的所有数据 现在 让我们使用手机添加数据 当然了 数据也会同步给 iPad 现在 因为我手中的遥控器 有着神奇的推送功能 任何时间我都可以进行推送 现在让我们 更真实一点 我要删除所有 从 iPhone 上面添加到 我的 iPad 的数据 只留下前四行 然后 我要做相同的事 在 iPhone 上删除所有 从 iPad 导入的数据 我之前使用了遥控器 现在 我不会再去 碰那个遥控器 我就继续播放视频 然后你们可以看到 当我拍摄视频时 这两个设备是如何同步数据的 对吧
虽然看起来不太自然 但很棒的是 仅仅点按了几下 我们就构建了一个 App 使用 Core Data 和 CloudKit 端对端同步数据 如果我不告诉你们 AppDelegate 中实际上隐藏了 15000 行代码 那就是我的不对了 所以让我们看看这部分代码
这是一个非常标准的 AppDelegate 事实上 如果你以前 用 Xcode 构建过 Core Data App 那你应该会非常熟悉 包括这部分 设置 Core Data 堆栈的代码 这个 App 唯一有些不同的地方 就是今年 Core Data 里面的一个新 API 叫做 NSPersistentCloudKitContainer 它的设计目的就是为了帮助你 来管理 CloudKit 数据库中 的 Core Data 存储
现在 如果你之前 就用 Xcode 做过 Core Data App 那么你在此处看到的是 NSPersistentContainer 它是 NSPersistentCloudKitContainer 的父类 正因如此 你可以只改一行代码 就给你现有的 Core Data App 增加 CloudKit 功能 所以到底什么是 NSPersistentCloudKitContainer 其实它是封装了 一套非常常见的模版 每个人都必须构建 才能使用 CloudKit 实现端对端同步 它可以让你省去 成千上万行代码的麻烦
它也是我们 今后希望和你们共同完成 不断迭代的基础 当然了 为了实现这个目标 说到重点了 我们需要你们的帮助
我们现在需要你们的反馈 比如 NSPersistentCloudKitContainer 效果如何 还缺失什么功能 亦或者在工作的过程中 现有功能是否满足了你 App 的需求 所以 让我再仔细介绍一下 它的部分功能 NSPersistentCloudKitContainer 可以为你的 App 提供本地副本 一个完全一致的 Core Data 或者 CloudKit 数据库镜像 它还具备健壮的 调度以及错误恢复事件循环 因此你的 App 完全不用担心 任何运维方面的问题 最后 它还有 NSManagedObject 实例 和 CKRecord 之间的 转化功能
现在本地副本非常重要 但是这意味着 当你的 App 处理对象时 它会将其写入 Core Data 管理的本地存储文件中 而且 它也会从本地存储文件中 读取对象 这是由于本地数据库 与云存储的性能不太相同 对吧 当我们谈到 访问本地文件的延迟 读取磁盘上的文件 都是以毫秒为单位 即使在最坏的情况下也是如此 然而如果通过网络 可能会花上几秒甚至几分钟 才能获取 App 所需的数据 同样地 本地存储 可以为你的 App 提供 更高的带宽 即使在我们的 iPhone 上面 可以以 gb/s 为单位 而云端的可用带宽 被限制在 kb/s 或者 mb/s
本地副本 必然将增加 程序的复杂性 因此 NSPersistentCloudKitContainer 需要一个健壮的调度和 错误恢复事件循环 所以当你的 App 将数据写入本地存储时 NSPersistentCloudKitContainer 自动将这些内容上传到云
当 CloudKit 上的内容发生变化 NSPersistentCloudKitContainer 就会在系统上调度工作 将这些对象 传输到你的本地数据库 供你的 App 使用 当然 在这个过程中 你的对象需要 被 NSPersistentCloudKitContainer 从 NSManagedObject 实例 转变为 CKRecord 实例
同样的 当有些内容 在云上发生变化 那些 CKRecord 实例 就会作为 NSManagedObject 实例 被存放在本地储存文件中 这就是 NSPersistentCloudKitContainer 可以为你的 App 所做的事 它就是一个 CloudKit 的 私人数据库本地副本 你要知道我们制作了一个特定区域 用于 Core Data 同步 我们实现了自动调度 因此你不用担心 如何优化操作 或在系统调度它们 我认为更重要的是 你无需担心 在 App 中实现任何 错误恢复逻辑问题
最后 我们实现了 从 NSManagedObject 到 CKRecord 的 自动序列化 并且我们是使用 NSManagedObject 模型实现的
如果我站在这里 告诉你们 只要采用 NSPersistentCloudKitContainer 你就将拥有一个 功能齐全的 App 那我就太愚蠢了 所以我就想用剩下的时间谈一谈 在 NSPersistentCloudKitContainer 的基础上 可以做到什么 我认为首先 要从利用 Core Data 制作优秀的 App 讲起 然后 我们再看一看 你如何能够扩展 我们在 NSPersistentCloudKitContainer 中已经构建的基础 以此来更精准地满足你的使用需求
现在 对于我来说 用 Core Data 来打造优秀的 App 需要用足够的知识 为此 我们今年已经写了 无数的文档来具体解释 NSPersistentCloudKitContainer 如何工作 以及如何将它融入到你的 App 中
Core Data 有很多功能 都可以搭配 NSPersistentCloudKitContainer 使用 比如 FetchResultsController 它可以帮助你 构建可扩展用户界面 并由大量数据支持 而查询生成则可以帮助你 维护界面的稳定性 在后台可能发生一些变化的时候 不受影响 比如来自 NSPersistentCloudKitContainer 的变化
最后 还需要回溯到几年前 我们曾经介绍过的内容 帮助你理解 数据库到底有了什么改变 并且有了 NSPersistentCloudKitContainer 你可以使用它来决定 后台更新是否与 你的用户正在做的事情有所关联 我们将在星期三的下午三点 对这些功能以及其他更多内容进行介绍 与此同时 我们今年还将推出 一款全新的 App 样例 让你们实际感受到 NSPersistentCloudKitContainer 和 Core Data 其他功能 共同工作的优势所在 它是用来管理 帖子的一款 App 而帖子是我们 过去几年在 Core Data 中 一直研究的主题 对吧 它们是很棒的对象 能让我们了解 对象图的不同部分 是如何受到 CloudKit 影响的 在这里 你可以看到 我们的数据模型非常简单 是吧 我们有一个标题 以及一些内容 然后 我们还有一堆标签 可以与每个帖子相关联 这款 App 甚至可以 让你看到 CloudKit 是如何管理照片的 App 允许你从设备的照片库 附加文件至帖子 现在 我们谈谈如何基于 NSPersistentCloudKitContainer 进行开发 正如你们所期待的那样 这一部分绝对是今天会议的重点 但是你们也应该知道 我们的文档其实包括 我们今天所讲内容的更多细节 所以不用担心 会漏掉什么内容 我们看到有很多客户用了不同的方法 扩展 NSPersistentCloudKitContainer 有的是从多个存储开始扩展 还有的客户 喜欢自定义 Schema 并用于 CloudKit 当然也用于 NSPersistentCloudKitContainer 你们都知道 因为 CloudKit 在很多平台都是可用的 不仅仅局限于 Apple 还适用于 Web Services 或者 JavaScript 所以你应该可以使用 NSPersistentCloudKitContainer 对象 即使不是在 Apple 的平台上 最后来看看 协同数据建模
现在 我们有很多理由 在 App 中使用多存储文件 尤其是处理网络存储时 多存储文件能够帮助我们 在 App 中 为不同的用例隔离数据 而且还能给我们 提供不同类型的限制 对吧 所以 如果我们想要 使用一个存储文件 管理一组非常特殊的验证限制 可能用于验证用户输入 我们可以为此 单独使用一个存储文件
多存储文件也能够很好的 来节流或合并设备上 频繁写的数据 当你从设备上读取的内容 产生自设备本身 或者产生自 创建数据的算法 这种情况可能就会发生 如果这个算法 产生数据的速度很快 那么持续同步到 CloudKit 就会极其昂贵 因此我们发现客户会嵌入 另外的存储文件 并使用它来合并数据 直到做好分析的准备再上传至 CloudKit 为了向你们展示工作原理 以及 Core Data 如何把这个过程 变得更加简单 我们将利用 NSManagedObjectModel 的一个名叫做配置的功能 现在 你们可以看到 我们的 App 示例 XCode 模型编辑器里面的 NSManagedObjectModel 现在 假设我想 在帖子中添加位置 对吧 我想记录下 帖子被创建时的位置 位置可以由系统高速生成 但我只有在帖子被创建时 才需要当前的位置 让我们将它们与 数据模型的其余部分分开
我将点按左下角 + 号 添加新的实体 存储我的位置信息 现在 我的位置信息将非常简单 它将只包括双精度的纬度和经度 即 Core Location 框架中提供的信息 当然 你也可以包括 其他方面的信息 如海拔或精度
现在 我们想将位置信息 与我们其他的数据隔离 为此 我将创建一个新的配置 再次点击这个 + 号按钮 但是这次 我将长按 直到出现一个菜单 可以让我添加配置 我将此配置命名为 Cloud 并且添加 全部的四个 需要同步的实体 现在你们可以看到 Cloud 配置中 这些我想要与 CloudKit 同步的实体 让我们创建一个新的配置 叫做 Local 用来储存我们的位置对象
仅仅几行代码 它就能为我们工作 允许 Core Data 自动告诉存储文件 存储对象的类型 第一行你可以看到我们创建了 一个 NSPersistentCloudKitContainer 实例 然后我们利用 NSPersistentStoreDescription 它可以告诉 NSPersistentCloudKitContainer 目前正在处理的 储存类型 我们创建的 NSPersistentStoreDescription 实例 指向 local.sqlite 文件 作为储存位置信息的地方 我们将其分配给 刚才创建的本地配置 然后 我们建立了自己的云存储 同样 我们创建一个 NSPersistentStoreDescription 实例 指向 cloud.sqlite 然后给它刚才的云配置 告诉 NSPersistentCloudKitContainer 只有类似帖子标签还有附件 图片这类内容才能在库中存储
最后 我们为它分配 NSPersistentCloudKitContainerOptions 的实例 它可以告诉 NSPersistentCloudKitContainer 这个存储应该与什么 iCloud 容器标识符同步 最后我们分配 这两个存储说明 给 PersistentStoreDescription 的 NSPersistentCloudKitContainer 属性
有了 NSPersistentCloudKitContainer 可以更好地利用它 我们现在已经有了本地存储 还有一个云存储 如果我们想要 在多个正在运行的 App 之间 共享一些存储在 CloudKit 的数据怎么办呢 NSPersistentCloudKitContainer 同样可以做到 事实上因为你在 使用 Core Data 是非常容易就可以 让你的 App 同时处理这些存储中的所有数据 并且 Core Data 还能自动帮助你处理 写入数据 自动插入到正确的存储文件里
仅仅加了三行代码 我们就能实现这个功能 对吧 我们创建一个新的 StoreDescription 然后指向我们分享的 存储文件 并且给它一个新配置 命名为 Shared 然后 我们给它分配 NSPersistentCloudKitContainerOptions 实例 它可以 指定容器 用于存储我们的共享数据 现在是 iCloud.com.wwdc.shared 当然 最后重要的一点 我们将给它分配一个 PersistentStoreDescriptions 现在谈谈 Schema 现在我想介绍 关于 Schema 的 几个重点 是当你在读取 CloudKit 中 创建的记录时 你需要知道的东西 我就从如何管理记录类型 以及管理实体开始讲起 这是你在 NSManagedObjectModel 创建的东西 然后 我们将看看 如何实现数据外化功能 也就是使用 NSPersistentCloudKitContainer 将任意大的数据 无缝存储在 CloudKit 最后 我们将谈谈 如何管理关系 它可能与你曾经使用 CloudKit 的经验有所不同 我们将在 App 样例中 使用 ManageObjectModel 然后我将从 Post 实体开始讲起 你可以看到它有两个属性 标题字符串 以及内容字符串 而且它还有两个关系 分别是对附件和标签实体
Core Data 可以为你生成一个类 在代码中使用 作为 NSManagedObject 的子类 看起来是这样的 你可以看到所有的属性和关系 都是在这个类中展示 这是 CloudKit 中 在帖子生成时创建的记录 这些都是我用来 填充记录的样例值 使记录具体化 现在 我还想与你们 强调另外一些事情 那就是记录 ID Core Data 有一个记录 ID 对应在 CloudKit 中 创建的每一个对象 对于每一个对象 都会生成一个简单的 UUID 作为其记录的名称 当这个记录名称与 区域标识符合并之后 你就得到了 CKRecord ID 下面两行你看到的是 Core Data 如何处理类型信息 这里有两个比较 有意思的事情 第一个是 CD_ 到底是什么意思
这是 Core Data 用来分开自身处理任务 和 CloudKit 为你运行的 任务的一种方式 你不会相信有多少人会给 CKRecord 添加修改日期 或者区分用户 自己添加的东西 因此 我们提前标好前缀 记录类型和所有的字段名称 都包含 CD_ 前缀 但是在 CD_entityName 字段 我们会保留 记录中对象实体的真实名称 这么做是为了 可以实现 实体继承的功能 你可以创建帖子的子类 比如 像是一个图像帖子或者是 视频帖子 实际的实体一般都会 被在 CD_entityName 标示出来 我们这么做是为了 在查询时 只要查询一个记录类型 就能得到所有你感兴趣的 实体层次结构
现在看看我们如何 实现这两个字符串 因为这些字段的长度是可变的 还有我们将其上传至 CloudKit 中时 也有很多有趣的习惯
你会看到我们已经将其 填充进四个字段中 而这么做的原因是 我们使用了 数据外化的方式 你可以看到我们 既有了 CD_content 又有了 CD_content_CKAsset 借此 我们可以储存字符串 无论它们有多长 从几 kb 再到几百 mb 甚至是以 gb 计算都可以储存
当我说 这个记录 已经进行了全部的具体化 我的意思是 你不会在同一时间 看到全部的四个字段 如果字符串很短 那么你会看到记录中有 CD_content 和 CD_title 但是 如果它们变得 非常很长 大于 750 kb 又或者整个记录的大小 超过了 CloudKit 的 1 mb 的限制 那么你就会看到 asset 字段 也就是现在的 CD_content_CKAsset 如果你需要一直 使用我们的记录 那你需要检查这两个字段 看看某个属性 是否被赋了某个值
现在看看 Post 里面的关系 你可以看到它们 都是 Core Data 为你在对象中创建且 可供你使用的 NSSet 实例 这是因为 Post 中 有我们所谓的 多元关系 这意味着 一个帖子 可以有多个附件 或者它可以有多个标签 我们一般称附件关系为 多对一 因为一个附件只能被分配给一个帖子
当我们写代码的时候 你可以看到 Post 中有一个 NSSet 但 Attachment ManageObject 仅有一个 Post 对象
这就是为附件生成的记录 你可以看到它已经有了一个 UUID 一个实体名称和记录类型 就像 Post 一样 但是你也看到了 这里有一个叫做 CD_post 的字段 这是我们如何储存 多对一的关系 在 CloudKit 中 相关记录的 UUID 始终会储存在与它相关联的对象中 并且 也许你会想 为什么我们不用 CKReference 来处理这个问题呢 那是因为 CKReference 有一些我们认为 对于 Core Data 客户来说 并不是很友好的地方 那就是它对象的数量只能限制在 750 之内 但是通过这样储存关系 你可以在 CloudKit 容器中 存储足够多的关系 现在看看多对多关系 在本例中 也就是帖子和它的标签之间的关系
你可以看到对象中 有两个 NSSet 这是因为两个对象都 与其他的很多类型相连 当我们生成 这些对象的记录时 我们没有具体化的字段 来存储这种关系 而是 Core Data 具体化了一种自定义连接记录 现在如果你对于 关系数据库很熟悉 你会理解这个概念 基本上来说 它就是 对于连接表中一行的外推 被叫做 CDMR 或者是 Core Data 镜像关系 CDMR 包含了一对元组 这是为了描述 两个相关联对象 首先是相关联对象的 实体名称 以及记录名称 我之前说过 这不是记录 ID 这是记录名称 需要你把它和 区域标识符结合起来 然后得到 CDMR 相连的记录的标识符 最后 我们也将此关联的 确切关系进行记录
那么为什么我要花费这么多时间 来和你们介绍关系呢
因为它们会影响我们 协作进行数据建模的方式 我也需要说清楚 协作并非冲突解决 冲突解决可以通过 NSPersistentCloudKitContainer 使用后写入为准的策略实现 我们这么做的原因是 冲突解决的作用是保持对象图 以及 CloudKit 中的数据 与你们建模的数据保持一致 但是 这些年来 一直进行的不尽如人意 那么 现在看看你如何使用关系 能更好地进行合并 并且将合并行为与特定用户用例保持一致
为了实现这个目标 我们将再次使用 Post App 我要创建一个帖子 但是我这次不会给它 分配任何内容
我就让它同步给另外一个设备 换句话说 我将同时在每台设备 上面进行一些编辑 现在 这才是我们 传统概念上称作的冲突 但是其实 这是一个 两台设备想要对 一个数值进行协同的好例子 现在 NSPersistentCloudKitContainer 已经发现 CloudKit 里面 的内容发生了改变 它将解决这个问题 以保留两个数值中的一个 是吧 使用后写入为准的策略 这就意味着要么我们 将协同做得很棒 要么要修改两次 的确如此 当然 也许你会想 嗯 这是多此一举的 Core Data 为什么不直接 连接两个字符串呢 我们的确能这么做 除非你在过去的几年里 采取了我们的建议实现了增量存储 否则结果可能会是这样 这不是我们想看到的 而且它甚至还不是英文
所以我们怎么才能改善呢 对吧 很明显 这是一个 不仅对我们 也是对客户来说 至关重要的问题 那么我们就看下 Post 实体 看看能做哪些改进 我们首要任务是停止 在表面值上创建冲突 内容只不过是表面上的字符串 我们没办法仅仅通过它本身推断 你想为字符串实行的 合并策略
但是 如果我们将它的关系进行分解 多个设备将对内容字段做出贡献 因为我们储存二对一关系的方式 很多设备可以在 同一时间里修改内容 而且不会对 Post 对象产生冲突
所以 我现在将其分解 使之变成一个由简单字符串 构成的 PostContent 实体
现在 因为我们存储 二对一关系的方式 这些将会由设备自行合并 对吧 我们得去研究它们 以此来收集最终值 我们将其称为最终一致性 当两台设备一起 修改 PostContent 对象的时候 它们就会从对方那里 下载 PostContent 对象 并将其连接或者合并 再或者其他你选择的连接方式 用来解决这个问题 以此收集最终值的操作
但是我们想让这个过程 在所有设备中都保持一致 不同的下载顺序 就可能导致最终值的不同 因此 我们要用一些信息 将它们排序 比如日期 这样做的话 设备就可以 在连接之前 使用 Core Data 中简单的排序描述符 对 PostContent 对象排序 使下载顺序和合并策略 在所有设备上保持一致 然而 我还是比较喜欢研究 分布式系统 而时间有其局限性
事实上 如果设备们都在你的房间中 那它们的时间 可能都不会有所差别
那么 我们可以把这一步 做得更远 利用修改的层级关系 并给予实体一些 关于正在进行实际工作的设备信息 从而实现完整的因果树 这样的话 我们就完成了 一个称作无冲突 复制数据类型的粗略草图 这是一个极棒的 新兴计算机科学领域 它可以帮助我们部署算法 在不同的用户-用户场景之间 生成一致的合并行为 这就是在 Using Core Data with CloudKit 的主要内容 我非常荣幸能够向你们展示 NSPersistentCloudKitContainer 以及对于你来说为自己的 App 实现 同步功能有多简单 今年 我们可以为你们提供 非常棒的示例代码和文档 并且我非常希望可以给你们带来 全新 API 的极致体验 最后 我已经迫不及待 想看看你们如何使用 NSPersistentCloudKitContainer 以及如何去扩展它 今年我们有很多实验室 这周每天都有 正如你们所知道的 我们会在 星期三的三点钟举办一个会议 届时 Core Data 更多的功能将亮相
非常感谢 我希望大家 都能好好享受 WWDC [掌声]
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。