【问题标题】:NSUserDefaults performance concernsNSUserDefaults 性能问题
【发布时间】:2016-09-26 06:40:01
【问题描述】:

我有一个游戏,我不断地保存用户进度。这是一款进度非常快的游戏,在游戏中的某些时候,巨大的用户进度可能每秒发生 6 次,这需要我在 NSUserDefaults 中存储一些进度变量并每秒同步 6 次。这在我的 iPhone6s 64gb 上运行良好,但我担心它可能不是 iPhone4 16gb 可以处理的。

我没有办法测试它,因为模拟器对这样的事情并不准确,而且我没有速度较慢的设备。我似乎也无法在文档中找到有关 NSUserDefaults 性能报告的许多详细信息。有人对此主题有任何了解吗?

我正在考虑将变量存储在本地 NSDictionary 中,我将在我的 .h 中定义,然后在 appWillResignActive 期间保存和同步一次 NSUserDefaults,但我担心在崩溃、设备电池耗尽等情况下会丢失数据. 我想我可以有一个 NSTimer 并每隔 5 秒左右保存一次数据,还可以保存在 appWillResignActive 上,以尽量减少崩溃时的损失;我宁愿不必重写我的大量代码,尽管 NSUserDefaults 可能能够在较小的设备上处理得很好。

【问题讨论】:

  • 请注意,调用“同步”与将数据写入磁盘无关。它纯粹是为了与另一个正在读取和写入相同默认存储的应用程序同步(这非常罕见,对于非 Apple 应用程序几乎不可能在 iOS 上使用)。 synchronize 很快(最终)将被弃用,因为它不像人们认为的那样做任何事情。请参阅其维护者关于正确使用 NSUserDefaults 的文章:dscoder.com/defaults.html
  • 谢谢@RobNapier 我不知道!
  • 虽然我同意这些答案,但你打电话给synchronize 太多了,我想指出你的“担忧”可能是没有根据的......实际上有多少用户还有 iPhone 4 吗? This link 表明市场份额仅为 1% 左右。我建议不要花费大量时间尝试优化 1%
  • @RobNapier synchronize 确实将内存中的更改保留到磁盘。在 iOS(可能还有 OS X)中,它由 plist 文件支持。此 plist 文件在调用 synchronize 时更新。当然synchronize 会不时被操作系统自动调用。明确地调用synchronize 有合法用途,但不像许多人错误地那样频繁。我在我的应用程序进入后台时使用它,并保存任何必须保留的关键值,即使应用程序在下一行代码中崩溃(这种需求非常少见)。
  • @rmaddy 根据 David Smith(NSUserDefaults 维护者,上面链接)的说法,NSUserDefaults 是由一个单独的进程编写的,因此即使您崩溃写入也会保留,并且“几乎从不需要调用 -synchronize设置偏好后。”这是我掌握的最好的信息。无论如何它已被弃用(“并且将在未来的版本中使用 NS_DEPRECATED 宏进行标记”)。请参阅第 164 行附近的 NSUserDefaults.h。

标签: ios performance nsuserdefaults


【解决方案1】:

NSUserDefaults 只是内存中的NSDictionary。只要您没有在每次设置值时都不必要地调用synchronize,就不会出现任何问题。操作系统将每隔一段时间保留内存中的表示。当然不是每秒多次。

因此,您可以随意使用NSUserDefaults。仅在极少数情况下调用 synchronize,例如当您的应用处于非活动状态或进入后台时。

【讨论】:

  • 我每次保存变量时都在调用同步哈哈,我将停止这样做——谢谢!
  • NSUserDefaults 只是内存中的一个 NSDictionary,除了它有额外的线程安全开销,更重要的是,它可能有观察者监视 UserDefaultsDidChange,每次访问都会在主线程上触发。我的分析表明,即使您自己没有添加它们也是如此。
【解决方案2】:

不要每秒调用 6 次同步。 (不要每秒执行 6 次任何基于磁盘的操作。)系统会为您保存用户默认值。如你所说,在 appWillResignActive 中调用 synchronize 是合理的,或者在级别之间。

如果您崩溃,预计会丢失一些数据。但是,编写良好的应用程序不应该崩溃。如果您经常崩溃,那是您的问题,而不是同步用户默认值。 (并不是说您的应用会这样做)

【讨论】:

  • 听起来不错,所以我将经常存储到 NSUserDefaults 并每隔一分钟左右在计时器上调用 synchronize 以及在 appWillResignActive 时调用
  • @AlbertRenshaw 没有理由每分钟都调用synchronize,除非您希望您的应用程序经常崩溃。
  • @rmaddy 我不希望我的应用程序崩溃;)但我认为安全总比抱歉更安全
猜你喜欢
  • 1970-01-01
  • 2011-08-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多