将使用核心数据的 iOS 应用同步到云端

Posted

技术标签:

【中文标题】将使用核心数据的 iOS 应用同步到云端【英文标题】:Sync an iOS app that uses core data to cloud 【发布时间】:2016-10-14 04:11:59 【问题描述】:

我已经使用 Swift 2 编写了一个应用程序,使用 Core Data 来实现持久性。我正在考虑添加一个功能以在云中也持续存在。我已经阅读了有关 Realm 和 CloudKit 的教程,但还没有看到在 Core Data 之上(或连同)使用它们的很好的例子。

我想:

    允许用户输入他们的数据一次,并使其显示在他们的所有设备上。 让用户将他们的部分数据与他们选择的用户同步。

我可以保留我的所有核心数据逻辑,并在使用 CloudKit(或其他框架)进行 CRUD 操作期间简单地添加一些服务器调用吗?例如,我对我的几个表使用NSFetchedResultsController,在使用 CloudKit 的同时继续使用它是否有意义?

【问题讨论】:

【参考方案1】:

CloudKitCoreData 不会自动无缝地协同工作,因此您需要自己编写该逻辑。

有different types of iCloud storage options,其中一两个可以与CoreData 无缝集成,但CloudKit 不是其中之一,如果您希望启用您的用户与他人共享数据。

又名:您需要自己完成繁重的工作,但如果您使用良好的设计实践,您可以一次性完成这项工作,而无需重写大部分现有代码。

所以,这与我在使用这两种框架的一个项目中所做的类似:

创建 Core Data 对象模型和 NSManagedObject 子类,你几乎肯定已经拥有了。

在 Xcode 项目功能中开启 CloudKit 并登录 CloudKit Dashboard

使用 CloudKit Dashboard 设计以 Core Data 实体模型为模型的记录模型

(返回 Xcode)在某处创建方法(最方便地作为 NSManagedObject 子类的扩展),知道如何从 CKRecord 创建给定的 Core Data 对象,并从 CKRecord 创建一个核心数据对象。

创建一个或多个 Swift 类,专门用于处理您的 CloudKit 记录并将它们与 Core Data 同步。这个类将负责执行所有 CloudKit 高级操作,包括获取、添加、删除、修改等。您可以根据需要设计这个公共 API(它应该根据您的需要进行定制),但这类很可能会使用您在上一步中创建的方法来转换核心数据类型。

通过这种方法,您的 CloudKit 专业课程(我们将其称为 CloudBrain)可以完成所有繁重的工作,如果您愿意,您可以在幕后完成所有工作。例如,您可以定义另一个类SyncBrain,它会自动侦听Core Data 托管对象上下文中的更改,并在CloudBrain 上调用相应的方法以确保所有更改都与iCloud 保持同步。它还需要做相反的事情,监听 iCloud 中的变化并将它们应用到 Core Data。这当然需要最初从 CloudBrain 获取更改,并且您还需要查看 CKSubscription 以获取实时更新。

这种方法的美妙之处在于,如果您正确设置所有这些,您可以保持所有其他代码相同,因为每次您的其他类与 Core Data 交互时,SyncBrain 自动确保所有更改核心数据反映在 iCloud 中,反之亦然。

至于与其他用户共享,此功能是 ios 10 中的新功能,似乎 Apple 尚未更新 CloudKit Quick Start。因此,今年你应该观看来自 WWDC 的What's New with CloudKit。

重要提示:在 CloudKit Dashboard 中设计记录模型时,请务必遵循iCloud Design Guide,并且不要让父记录类型的字段包含子记录类型的数组。这不是很好的表现。相反,将子记录类型定义为具有指向其父级的单个 CKReference 字段。这样,如果您需要子代作为父代,您只需创建一个查询,请求所有对象的父代设置为您想要的父代(而不是在您想要的只是等待所有子代下载时)父母)。

这里有一些 WWDC 会议。较早的会话仍然包含非常有用的信息,但其中一些已过时。

2014 – Introducing CloudKit(正确理解概念的必看点) 2014 – Advanced CloudKit 2015 – What's New in CloudKit 2015 – CloudKit Tips and Tricks 2016 – What's New with CloudKit 2016 – CloudKit Best Practices

【讨论】:

这真的很有帮助,谢谢。我可能会走那条路。我需要编写自己的逻辑并跟踪“脏”数据吗?例如,如果用户在时间 T 在设备 A 上输入数据,然后在设备 B 上打开应用程序,它的最后一次更新是在时间 T-1,然后从 iCloud 拉取 T-1 之后的所有输入? @Coder1224 CloudKit 内置了对更改标签的支持,这将帮助您处理一些事情,但是您需要处理诸如数据不同步之类的事情,因为每个应用程序都可以选择处理它不同。观看 2014、2015 和 2016 年的一些 CloudKit WWDC 会议可能会对这一领域有所帮助。我会用一些链接更新我的帖子。 感谢您的链接,我实际上都看过了。他们都有有用的东西,我同意第一个是必须的。他们都提到了在本地缓存东西,当然我正在使用 Core Data。您认为我将所有数据保存在本地可以吗?我没有看到任何 WWDC 会谈解决这个问题。我想我会大量使用“更改标签”和CKFetchRecordChangesOperation @Coder1224 将所有数据也存储在本地可能是个好主意,这样用户仍然可以离线访问所有内容。 CKFetchRecordChangesOperation 也是一个好用的东西,但根据我的经验,我很难让 CloudKit 准确地返回所有更改。 我已经取得了一些不错的进展,让事情正常进行。当我的核心数据对象被添加/更新/删除时,我已经能够在 iCloud 中添加/更新/删除。我遇到了当用户删除时该怎么做的问题,例如,在离线时?我正在考虑添加一个 addedQueue、modifiedQueue 和 deletedQueue,并使用NSCoding/NSKeyedArchiver 将它们持久化,然后尝试在后台或每次应用启动时将它们出列。这听起来合理吗?您对这个问题有何经验?【参考方案2】:

在 Xcode 11 中,您现在可以将 Core Data 镜像到云端。这似乎也很容易做到。您只需要使用NSPersistentCloudKitContainer 而不是NSPersistentContainer。您的数据将自动与 CloudKit 同步。

请参阅documentation 了解更多信息。

PS。在撰写本文时,它处于测试阶段。

【讨论】:

你知道新的 NSPersistentCloudKitContainer 是否可以与其他人共享数据,而不仅仅是在单个用户的设备之间(CKShare)吗? @Rob 我也有同样的问题。新的同步可能性很棒,但我需要共享数据的能力。现在,您可以使用 objectID 访问特定记录(请参阅developer.apple.com/documentation/coredata/…)并从中创建一个 CKShare但是:如果您有您要共享很多实体,您需要它们具有相同的父记录(否则您必须分别共享它们中的每一个)。这是一个关键问题:Apple 的新自动同步功能不适用于原生 CloudKit 引用,而是使用外键...... 实际上我所有的实体共享一个父记录。我的应用程序允许用户共享一个“商店”,每个“商店”都有“产品”、“员工”、“销售收据”等......例如。但是,它们都指向父“Store”;因此,当用户共享“商店”时,他们会获得所有从属实体。但我仍然认为这不会奏效,因为 Apple 在私有数据库中维护了一个自定义区域。由于记录保存在私有数据库中,我的想法是 CKShares 将不可用,但希望我错了。

以上是关于将使用核心数据的 iOS 应用同步到云端的主要内容,如果未能解决你的问题,请参考以下文章

将 iOS 应用中的数据同步到 OS X 应用中的核心数据

如何将现有核心数据 iOS 7 应用程序的数据迁移到 iCloud?

Dropbox 核心 API 和同步 API

同步核心数据:iOS 到 OSX,反之亦然

评估将核心数据与 Dropbox 同步的策略

WatchKit 核心数据同步