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

5
我使用Swift 2和Core Data进行持久化编写了一个应用程序。现在我想添加一个功能,使其也能够在云端持久化。我已经阅读了有关Realm和CloudKit的教程,但没有看到如何在Core Data上使用它们的好例子。
我的目标是: 1. 允许用户只输入一次数据,然后在所有设备上都可以访问。 2. 让用户将他们的一些数据与其他用户同步。
我是否可以保留所有Core Data逻辑,并在CRUD操作期间添加一些服务器调用来使用CloudKit(或其他框架)?例如,我为多个表使用NSFetchedResultsController,那么在使用CloudKit时继续使用它是否有意义?
2个回答

16

CloudKitCoreData不能自动无缝地协同工作,所以您需要自己编写逻辑。

不同类型的iCloud存储选项,其中一两个与CoreData无缝集成,但CloudKit不是其中之一,如果您希望让用户与其他人共享数据,则需要使用CloudKit

即:您需要自己费力编写代码,但如果使用良好的设计实践,可以只做一次工作而不必重写现有代码。

因此,以下是类似于我在使用两个框架的项目中所做的内容:

  • 创建Core Data对象模型和NSManagedObject子类,就像您几乎肯定已经做过的那样。

  • 在Xcode项目能力中打开CloudKit并登录到CloudKit Dashboard。

  • 使用CloudKit Dashboard根据您的Core Data实体模型设计记录模型。

  • (回到Xcode) 在某个地方创建方法(最方便的方式是作为NSManagedObject子类的扩展),使其知道如何从CKRecord创建给定的Core Data对象,并从Core Data对象创建CKRecord

  • 创建一个或多个专门处理CloudKit记录并将其与Core Data同步的Swift类。该类将负责在高级别上执行所有CloudKit操作,包括获取、添加、删除、修改等。您可以根据需要设计此公共API,但是该类最有可能使用先前步骤中创建的方法将类型转换为和从Core Data类型转换。

通过这种方法,你的CloudKit专业类(我们称之为CloudBrain)完成了所有繁重的工作,如果你想要的话,你可以让它在幕后完成所有工作。例如,你可以定义另一个类,SyncBrain,它会自动监听Core Data受管对象上下文中的更改,并调用CloudBrain上的相应方法,以确保所有更改都与iCloud同步。它还需要反向操作,监听iCloud中的更改并将它们应用于Core Data。当然,这将首先需要从CloudBrain获取更改,你还需要了解CKSubscription以进行实时更新。
这种方法的美妙之处在于,如果你正确设置了所有这些内容,那么你可以保持所有其他代码不变,因为每次其他类与Core Data交互时,SyncBrain会自动确保Core Data中的所有更改都反映在iCloud中,反之亦然。
至于与其他用户共享,这个功能在iOS 10中是新的,而且似乎苹果还没有更新CloudKit Quick Start。因此,你应该观看今年WWDC的CloudKit有什么新功能

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

以下是一些WWDC会议。较旧的会议仍然包含非常有用的信息,但其中一些已过时。


非常有帮助,谢谢。我可能会选择这条路线。我需要编写自己的逻辑并跟踪“脏”数据吗?例如,如果用户在时间T在设备A上输入数据,然后在设备B上打开应用程序,其最后更新时间为T-1,则是否需要从iCloud拉取T-1之后的所有输入? - Coder1224
@Coder1224 把所有数据都本地存储也许是个好主意,这样用户就可以在离线情况下访问所有内容。CKFetchRecordChangesOperation 也是一个不错的选择,但根据我的经验,我曾经遇到过 CloudKit 无法准确返回所有更改的问题。 - Matthew Seaman
我已经取得了一些进展,使事情正常运作。当我的Core Data对象被添加/更新/删除时,我能够在iCloud中进行添加/更新/删除操作。但是,我遇到了一个问题,如果用户在离线状态下执行删除操作该怎么办?我正在考虑添加addedQueue、modifiedQueue和deletedQueue,并使用NSCoding/NSKeyedArchiver进行持久化,然后尝试在后台或每次应用程序启动时出队列。这听起来合理吗?你对这个问题有什么经验? - Coder1224
我在这里发布了一个单独的问题:http://stackoverflow.com/questions/40292321/cloudkit-what-to-do-when-a-user-adds-modifies-or-deletes-an-object-while-offl - Coder1224
是的,今年的WWDC会议介绍了新的方法来实现这一点,但我个人还没有使用过新的对象,因为我不再管理我曾经工作过的CloudKit应用程序。在发布我的先前评论时忘记了这一点。 - Matthew Seaman
显示剩余4条评论

4

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

更多信息请参见文档

附言:截至撰写本文时,此功能处于beta测试阶段。


1
你知道新的NSPersistentCloudKitContainer是否适用于与他人共享数据,而不仅仅是在单个用户设备之间共享(CKShare)吗? - Rob
@Rob 我也有同样的问题。新的同步功能非常棒,但我需要分享数据的能力。现在,你可以通过使用(请参阅https://developer.apple.com/documentation/coredata/nspersistentcloudkitcontainer/3141668-record)的objectID访问特定记录,并从中创建CKShare,*但是*:如果你有很多实体要分享,你需要它们具有相同的_parent record_(否则,你必须单独分享每个实体)。而且这里是一个关键的问题:苹果的新自动同步不使用本地CloudKit引用,而是使用外键。 - Victor Pro
实际上,所有我的实体都共享一个父记录。 我的应用程序允许用户共享“商店”,每个“商店”都有“产品”,“员工”,“销售收据”等等......例如。 但是,它们都指向一个父级“商店”; 因此,当用户共享“商店”时,他们会获得所有下属实体。 但我仍然不认为这会起作用,因为苹果在私人数据库中维护自定义区域。由于记录保存在私人数据库中,我的想法是CKShares将不可用,但希望我是错的。 - Rob
你的数据理论上会自动与CloudKit同步。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接