何时(不)滥用 NSUserDefaults
Posted
技术标签:
【中文标题】何时(不)滥用 NSUserDefaults【英文标题】:When (not) to abuse NSUserDefaults 【发布时间】:2011-07-28 02:34:33 【问题描述】:我想知道这些指南的用途: 1 - 我多久可以读取一次 NSUserDefaults 2 - 我可以在 NSUserDefaults 中合理存储多少数据
显然,可以使用多少 NSUserDefaults 是有限制的,但我无法确定什么是合理的,什么不是。
一些例子:
如果我的游戏有让计算机成为玩家之一的选项,我将使用 NSUserDefaults 来保存该布尔值。这很清楚。但是,每次我想知道计算机是否是玩家时,在我的游戏期间访问 NSUserDefaults 是否也是合理的,或者我应该为此使用实例变量吗?假设我需要每秒检查一次布尔值。答案是否相同,而是 100 毫秒?每 10 秒呢?
如果我的游戏有 50 个移动对象,并且我希望在用户退出应用程序时存储它们的位置和速度,那么 NSUserDefaults 是存储该数据的合理位置吗? 20个移动物体呢? 200个呢?
【问题讨论】:
【参考方案1】:在 NSUserDefaults 中数百到数千个项目都可以(它基本上只是属性列表序列化的一个包装器)。关于应用程序的开销,最好的办法是尝试并使用分析器。
【讨论】:
感谢您提到使用分析器。你是我的英雄。【参考方案2】:我想知道这些准则的用途是: 1 - 我多久可以从 NSUserDefaults 读取一次
相当有规律。期望默认值的开销类似于线程安全的 NSDictionary
2 - 我可以在 NSUserDefaults 中合理存储多少数据
实际上,超出您的需要。逻辑最大值是您需要它有多快,以及它在磁盘上占用多少空间。还请记住,在启动/关闭和其他各种时间,这种表示会被读写到磁盘或从磁盘读取。
如果我的游戏有让计算机成为玩家之一的选项,我将使用 NSUserDefaults 来保存该布尔值。这很清楚。但是,每次我想知道计算机是玩家还是我应该使用实例变量时,在我的游戏期间访问 NSUserDefaults 是否也合理?
只需将const bool
添加到对手对象即可。零运行时损失,除了内存,这并不重要。
假设我需要每秒检查一次该布尔值。答案是否相同,而是 100 毫秒?每 10 秒呢?
再次,它就像一个线程安全的 NSDictionary(散列)。它将相当快,并且足够快以该频率阅读。它是否是最好的设计取决于程序。如果它变得巨大,那么是的,性能会受到影响。
如果我的游戏有 50 个移动对象,并且我希望在用户退出应用程序时存储它们的位置和速度,那么 NSUserDefaults 是存储这些数据的合理位置吗? 20个移动物体呢? 200个呢?
它会很好,虽然我不会在玩游戏期间通过用户默认值进行读/写;只需根据需要保存/加载状态。
我不建议将所有这些保存在用户默认值中。只需为您的游戏状态创建一个文件表示并使用用户默认值来设计它。如果它很大并且您经常写入它,那么实现可能会定期将状态刷新到磁盘,这可能需要相对较长的时间。
【讨论】:
关于你的最后一段,每 1 到 5 次状态变化刷新到磁盘,或者使用计时器每分钟执行一次。【参考方案3】:不用担心限制。相反,问自己这个简单的问题:
这是一种偏好吗?
如果它是一个偏好,那么它应该在用户默认值中。这就是用户默认值的用途。如果没有,那么它应该在 Documents 目录中(或者,在 Mac 上,可能在 Application Support 中)。
在 ios 上,您可以通过是否适合(如果可能)将其放入设置包中以在“设置”应用程序中显示和编辑来判断它是否是首选项。在 Mac OS X 上,您通常可以通过将其放在“首选项”窗口中是否合适来判断它是否是首选项。
当然,这取决于您的判断。例如,Stanza for Mac 就出错了,将非首选项放在其首选项窗口中。
你也可以通过它的反面来考虑这个问题:
这是用户创建的数据吗?
您将拥有默认值的首选项不是用户创建的数据;它是用户覆盖的数据。丢失它同样糟糕,但它会告诉你应该把它放在哪里。
【讨论】:
感谢大家的回复。这很有帮助。【参考方案4】:这里没有人提到的主要性能问题是用户的主目录可能在网络卷上,并且可能不是特别快。这不是一个理想的情况,但它确实发生了,所以如果您担心性能,那么您应该进行测试。
也就是说,NSUserDefaults
使用内存中的缓存,并且仅在同步时才会产生成本。根据文档,同步“自动……定期”发生;不过,我相信这仅适用于发生变化的情况。
因此,对于检查计算机是否为播放器的情况,使用NSUserDefaults
一次帧应该没有问题,因为它已被缓存。对于存储游戏状态,如果您不断更新它可能会出现性能问题,正如 Peter Hosey 所说,这是一种语义滥用。
【讨论】:
【参考方案5】:NSUserDefaults 基本上是一个包装器,用于从磁盘中的 .plist 文件加载 NSDictionary(并将其写入磁盘)。您可以在 NSUserDefaults 中存储尽可能多的数据,但您几乎无法控制它使用多少内存,以及它如何从磁盘读取。
我会针对不同的信息/数据使用不同的技术。
来自服务器、首选项、用户信息等的少量数据,我会使用 NSUserDefaults。
对于登录信息(访问令牌、敏感数据),我会使用钥匙串。钥匙串也可用于在删除应用时不应删除的数据。
对于大量的服务器数据或游戏数据,我会将其写入磁盘,但保留在内存中。
在您的情况下,我会将其保存在内存中(可能是 @property),但我会定期将其写入磁盘(可能每 1 到 5 次更改一次,使用 int ivar)。确保这个磁盘写入方法在 AppDelegate 中,这样当你关闭正在执行它的视图控制器时它不会失败。
这样,数据很容易被访问,但它也被保存到磁盘中安全保存。
【讨论】:
以上是关于何时(不)滥用 NSUserDefaults的主要内容,如果未能解决你的问题,请参考以下文章