5

我的应用程序使用 NSUbiquityKeyValueStore(一组对象)在 iCloud 中存储单个键值对。当数组中的任何对象发生更改时,整个数组都会保存到 iCloud。只要每个设备都有机会在本地进行更改之前下载最新的更新,这将非常有效。否则,本地更改可能会在其他设备的最新更新被拉下之前被推送到 iCloud,并且这些更新会在所有设备上丢失。这是我的应用程序的缺点还是 iCloud 的缺点,我该如何防止这种情况发生?

4

4 回答 4

2

否则,本地更改可能会在其他设备的最新更新被拉下之前被推送到 iCloud

本周我在一个正在从事的项目中遇到了类似的问题。我只是确保在收到来自 iCloud 的第一个更新之前,我没有将任何内容推送到 iCloud 服务器。此外,FWIW,我在初始化后立即设置了一个假键值对,以便它立即更新。

HackyStack 的本地标志的想法也是一个很好的解决方案;如果有变化,您可以询问用户是否要使用它。(有点像 Kindle 询问您是否要更新到最新页面)。

于 2012-11-17T14:46:36.903 回答
0

您应该阅读 -[NSUbiquitousKeyValueStore 同步] 的文档。它让您对何时使用它以及它的限制有一个很好的了解。特别要注意的是,它没有承诺何时实际同步数据,并暗示更新每分钟最多只上传几次(这可能适用于设备作为整个,而不仅仅是您的应用程序)。

键值存储机制旨在非常简单,仅用于非必要数据,通常是有关您的应用程序的配置信息。基本上,您不应该在其中存储用户数据或任何类似的东西。对于此类数据,请使用基于文件的 iCloud API。它们更复杂,但有了它们,您可以更深入地了解数据的同步状态,最重要的是,您可以收到冲突通知并提供自己的合并处理程序。

于 2012-11-29T22:06:54.863 回答
0

我不确定我是否完全理解确切的问题,但我相信答案要么是 NSObject 上的一个类别(你可以有一个“版本”属性)来检查对象的“版本”,或者你需要另一个键值配对以存储在 iCloud 上的“版本”,可以与本地存储在设备上的版本(lastUpdateVersion)进行比较,以了解您的立场。如果你能给我一个关于你的问题的真实世界的例子,我可以回答得更好......可能你甚至不需要一个“版本”,而是一个标志(BOOL)。

于 2012-11-15T17:35:02.717 回答
0

这是我的应用程序的缺点还是 iCloud 的缺点,我该如何防止这种情况发生?

这是 iCloud 的应用程序缺陷和预期行为。您可以通过多种方式对此进行解释,但总的来说,这并不容易。特别是对于 >2 台设备,在某些情况下,冲突的更改将永远不会呈现给设备进行解决,因为一般来说 iCloud 行为是“最后更改获胜”(请参阅​​下面的详细描述)。一些想法:

  • 而不是使用对象数组,而是为每个对象使用单独的键。显然这取决于你的应用程序的语义,但如果对象本质上是独立的,那么这通常会给你的应用程序它所期望的行为
  • 如果所有项目都是相互关联的,那么您将不得不自己解决冲突。做到这一点的最佳方法将在很大程度上取决于您的应用程序 + 数据语义。例如,也许您可​​以为数组或数组中的某些对象添加时间戳。您可以为每次保存使用新的密钥名称,以便所有设备最终获得所有密钥并解决冲突(显然这可能会快速消耗存储空间!)。解决冲突可能不值得做,这取决于您已经在本地存储的内容来帮助解决这个问题

背景

我最近有理由NSUbiquitousKeyValueStore在一些(乏味的)深度研究变革冲突这个话题。我在两个旧的 WWDC 视频中找到了一些信息,这些视频扩展了当前的 Apple 文档,特别是 WWDC11 Adopting iCloud Storage,第 1 部分(目前在此处可用,可通过此处找到)在 17:38 和随后的位置(例如 19:27)。另一个是 6:30 和 10:55 的 WWDC12 iCloud Storage Overview 演讲(这里最初是通过这里)。我随后通过运行两台设备验证了下面描述的行为,一台运行 iOS 15.2 的 iPhone 8 和一台运行 iOS 12.4 的 iPad Air 2,其中包含一个测试程序和大量控制台登录 Xcode。以下是我对解决冲突的预期行为和机制的最佳猜测。

概括

当设备使用 保存单个密钥时,密钥中包含NSUbiquitousKeyValueStore.default.set(value, forKey: key)一个隐藏timestamp的密钥以及该呼叫的设备时间。如果/当操作系统与键值存储的 iCloud 副本同步时,它会检查timestamp每个键的 s,如果 iCloudtimestamp时间较早,它会将新的键值保存timestamp到 iCloud 键值存储中。如果保存了键值,则当前已注册并在线接收通知的设备将被通知该键已更改,并且可以根据需要获取新值。如果 iCloud 不保存密钥值,任何设备上都不会发生任何通知,并且更改会被丢弃。

笔记

  • 如果此 iCloud 帐户上的所有设备在使用时都在线(注意低功耗模式、互联网连接不佳等),结果通常正是您想要的:应用程序进行更改,保存在 iCloud 中,传播到其他设备。如果设备已注册通知,通知会按预期发生。
  • 如果设备 A 保存了一段value时间它处于离线状态,而另一个设备 B 稍后保存了一段value时间它处于在线状态,则设备 A 上线,设备 A 的更改将被忽略,因为 iCloud 现在有一个较新valuetimestamp. B 永远不会被告知 A 的变化。但是,如果 A 已注册更改,A收到更新的 B 的通知,value然后可以决定是否应重新提交其值。
  • 由于这种“最后获胜”的行为,因此应该将属于一起的多个值一起保存为字典或数组,正如各种 Apple 文档和谈话中所建议的那样。
  • 不交互的值应保存为单独的键 - 从而允许来自多个设备的最新更改成功混合。
  • 没有自动化的方法来测试这些行为。回到 Xcode 9 天,可以为两个模拟器编写 UI 脚本来验证同步是否按预期工作,但这有一段时间没有奏效,这使得手动测试成为一个糟糕而乏味的替代品。
  • NSUbiquitousKeyValueStore除了简单的应用程序设置之外,它是许多场景的绝佳解决方案。就我个人而言,我希望看到更多的密钥(例如 10k 而不是 1k),但是设置的简单性和与客户的 iCloud 配额分开存储通常是一种乐趣。

在设备并不总是可靠连接的现实环境中,没有完美的解决方案。事实上,一些客户可能会故意保留旧 iPad,大部分时间处于离线状态,以在间歇性使用之间节省电池电量。如果您可以将同步数据保存在小的离散单元中并为每个键保存一个值,则同步通常会按预期工作。

于 2022-01-03T04:27:36.727 回答