我正在为我目前正在开发的 Core Data 应用程序集思广益地讨论云同步解决方案。我计划在完成后为此开源代码,供任何人与他们的 Core Data 应用程序一起使用,因此非常感谢来自社区的关于该系统应该如何工作的意见:-) 以下是我的想法:
服务器端
存储提供商
与所有云同步系统一样,存储是难题的主要部分。有很多方法可以处理这个问题。我可以设置自己的存储服务器,或使用 Amazon S3 之类的服务,但由于我以 0 美元的资本开始,因此目前付费存储解决方案不是可行的选择。经过一番思考,我决定与 Dropbox 和解。 (已经成熟的云同步应用程序和存储提供商)。使用 Dropbox 的优点是:
如果我决定将来切换到不同的存储提供商,我打算将“服务”添加到这个云同步框架,基本上允许任何人创建一个服务类来与他们选择的存储提供商进行交互,然后可以简单地插入到框架中。
存储结构
这是一个很难弄清楚的部分,所以我需要尽可能多的输入。我一直在考虑这样的结构:
CloudSyncFramework
======> [app name]
==========> devices
=============> (device id)
================> deviceinfo
================> changeset
==========> entities
=============> (entity name)
================> (object id)
对这种结构的快速解释:
[[UIDevice currentDevice] uniqueIdentifier]
的方式获取。 (在 iOS 上)或序列号(在 Mac OS 上)。 NSKeyedArchiver
归档到文件中的简单 NSDictionaries。 . 同时同步
这是我几乎完全一无所知的领域之一。 我将如何处理同时连接和同步云的 2 台设备? 这里似乎存在不同步甚至数据损坏的高风险。
处理迁移
再一次,这里是另一个毫 headless 绪的区域。 我将如何处理 Core Data 托管对象模型的迁移? 这里最简单的方法似乎只是将云数据存储区擦干净,然后从经过迁移过程的设备上传数据的新副本,但这似乎有点冒险,可能还有更好的方法。
客户端
将 NSManagedObjects 转换为 JSON
将属性转换为 JSON 并不是一项非常艰巨的任务(网上有很多关于它的代码)。关系是这里的关键问题。在 this stackoverflow 帖子中,Marcus Zarra 发布了将关系对象本身添加到 JSON 字典的代码。但是,他提到这可能会导致无限循环,具体取决于模型的结构,我不确定这是否适用于我的方法,因为我将每个对象存储为一个单独的文件。
我一直试图找到一种方法来获取 ID 作为
NSManagedObject
的字符串.然后我可以将 JSON 中的关系保存为 ID 数组。我发现的最接近的是 [[managedObject objectID] URIRepresentation]
,但这实际上并不是对象的 ID,它更多的是对象在持久存储中的位置,我不知道它是否足够具体以用作对象的引用。我想我可以为每个对象生成一个 UUID 字符串并将其保存为一个属性,但我愿意接受建议。
将更改同步到云
为此我想到的第一个(也是最好的)解决方案是听
NSManagedObjectContextObjectsDidChangeNotification
获取已更改对象的列表,然后在云数据存储中更新/删除/插入这些对象。保存更改后,我需要更新 变更集每个其他已注册设备的文件以反射(reflect)新更改的对象。这里出现的一个问题是,我将如何处理失败或中断的同步? .我的一个想法是首先将更改推送到云上的临时目录,然后在确认成功后将其与云上的主数据合并,这样同步过程中的中断就不会损坏数据。然后我会将需要在云中更新的对象的记录保存到 plist 文件或其他文件中,以便在下次应用程序连接到互联网时推送。
检索更改的对象
这相当简单,设备下载它的变更集文件,找出哪些对象需要更新/插入/删除,然后采取相应的行动。
这总结了我对该系统将使用的逻辑的想法:-) 非常感谢任何见解、建议、问题答案等。
更新
经过大量思考和阅读 TechZens 的建议,我对我的概念进行了一些修改。
我想到的最大变化是让每个设备在云中都有一个单独的数据存储。基本上,每次托管对象上下文保存 (感谢 TechZen),它会将更改上传到该设备的数据存储。更新这些更改后,它将创建一个包含更改详细信息的“更改集”文件,并将其保存到正在使用该应用程序的其他设备的更改集文件夹中。当其他设备连接到同步时,它们将通过变更集文件夹并将每个变更集应用到本地数据存储,然后也在云中更新各自的数据存储。
现在,如果使用该帐户注册了新设备,它将从所有设备中找到数据的最新副本,并将其下载以用作其本地存储。 这就解决了同步同步的问题并且减少了数据损坏的机会,因为没有“中央”数据存储,每个设备只接触它的数据,只是更新更改,而不是每个设备同时访问和修改相同的数据。
有一些明显的冲突情况需要处理,主要与删除对象有关。如果正在下载变更集,指示应用程序删除当前正在编辑的对象等,则需要有办法解决这个问题。
最佳答案
你想看看这个对云同步的悲观看法:Why Cloud Sync Will Never Work.
它涵盖了您正在努力解决的许多问题。其中许多在很大程度上是难以处理的。
同步信息周期非常、非常、非常困难。添加不同的设备、不同的操作系统、不同的数据结构等,往往会导致复杂性的增加。自 70 年代以来,人们一直在研究这个问题的变体,但情况确实没有太大改善。
根本问题是,如果您让系统保持灵活和可定制,那么同步所有变化的复杂性会随着定制数量的增加而呈指数级增长。如果你让它僵化,你可以同步,但你可以同步的内容是有限的。
How would I handle 2 devices connecting and syncing with the cloud at the same time?
弄明白了,你就发财了。对于当前的云同步提供商来说,这是一个大问题。他们真正的问题是你没有“同步”你的合并。软件在合并方面很糟糕,因为它很难建立一个预定义的规则集来描述所有可能的合并。
最简单的系统是建立规范设备或设备层次结构,以便系统始终知道要选择哪个输入。然而,这破坏了灵活性。
How would I handle migrations of the Core Data managed object model?
Core Data 模型的迁移在很大程度上与服务器无关。这是 Core Data 自己内部管理的东西。模型迁移更新模型,即实体图,而不是实际数据。
Converting NSManagedObjects into JSON
建模关系很难,尤其是使用不像 Core Data 那样容易支持它的工具。但是,永久托管对象 ID 的 URI 应该用作 UUID,将对象固定到特定设备上特定存储中的特定位置。它在技术上并不能保证是普遍独特的,但对于所有实际目的来说都足够接近。
Syncing changes to the cloud
我认为您将 Core Data 的实现细节与云本身混淆了。如果您使用
NSManagedObjectContextObjectsDidChangeNotification
每次观察到的上下文发生变化时,您都会唤起网络流量,无论这些变化是否持续存在。根据应用程序的不同,这可能会在几分钟内插入连接数千次。相反,您只想在最多保存上下文时进行同步。One problem that comes up here is, how would I handle a failed or interrupted sync?
在同步完成之前,您不会提交更改。这是一个大问题,会导致数据损坏。同样,您可以拥有灵活性、复杂性和脆弱性或不灵活、简单性和稳健性。
Retrieving changed objects: This is fairly simple, the device downloads its changeset file, figures out which objects need to be updated/inserted/deleted, then acts accordingly
如果您有一个不灵活的数据结构,这很简单。描述对灵活数据结构的更改是一场噩梦。
不知道我是否帮助过任何人。这些问题都没有优雅的解决方案。大多数设计人员最终都采用僵化和/或缓慢的蛮力迭代合并。
关于macos - 核心数据云同步 - 需要逻辑方面的帮助,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3327752/