NSUserDefaults的限制有哪些?

46

在 iPhone 上永久存储数据通常使用 Core Data 或 sqlite3,而大多数人更喜欢将 NSUserDefaults 用作应用程序首选项的存储,而不是像 sqlite 那样使用它作为普通数据库。

我发现可以在 NSUserDefaults 中存储大量数据,它非常易于使用且速度很快。那么为什么不将其用作永久存储呢?NSUserdefaults 作为数据库的限制有哪些?

更新:
我经常使用三种不同的方式将数据保存到磁盘中。

  • Core data
  • 对象序列化为 plists
  • NSUserDefaults

我不再使用 FMDB(或直接使用 sqlite)了。每种方法的主要优缺点是什么?

我遇到的一些 NSUserDefaults 优点:

  • 使用 NSPredicate 可以轻松完成排序、分组等操作。
  • NSUserDefaults 是线程安全的。
  • 只需一行代码就可获取和保存数据到 NSUserDefaults。

sqlite3更有效地保持大型数据库,搜索更快,并且具有许多特权。 - Viktor Apoyan
但是在NSUserDefaults中存储数据会在有大量数据时引起任何问题吗?SQLite3具有什么特权? - SEG
2
第一个和主要的优势是,您可以在sqlite3数据库中快速进行排序、分组和搜索。 - Viktor Apoyan
4个回答

16

Sqlite3在保留数据库元素的同时,更适合于存储大型数据库,并具有许多NSUserDefaults没有的特权!您可以对Sqlite3数据库的项目进行排序和快速搜索。


NSUserDefaults与Sqlite3

NSUserDefaults用于用户首选项,通常是像NSString或NSNumber这样的基本对象。而Sqlite、将对象集合序列化为属性列表,以及Core Data都是存储用户数据(如您创建的模型对象)的有效选项。

虽然你看不到速度差异,但最好选择正确的机制来处理你要做的事情。如果只是首选项,请使用NSUserDefaults;否则,我会将对象序列化为plist。如果你是Cocoa的新手,最好先避免使用Core Data或甚至Sqlite,给自己学习基础的机会。


NSUserDefaults或Sqlite

当你想要存储大量关系数据时,请使用Sqlite,如果要存储少量值,请使用NSUserDefaults。由于Sqlite占用一定的内存,因此只有在真正需要保存复杂数据时才使用它。


使用NSUserDefaults保存大量游戏数据

通常,NSUserDefaults用于保存游戏设置。要保存游戏数据,通常最好使用SQLite或创建对象NSDictionary并保存到磁盘上。以下是一些可能有帮助的帖子:

  1. http://www.cocos2d-iphone.org/forum/topic/9308
  2. http://www.cocos2d-iphone.org/forum/topic/9210

不是真的。这就是我想知道的。谢谢。 - SEG
1
@ViToBrothers 如果我们将字典存储在NSUserDefaults中会怎样? - rptwsthi
@rptwsthi,这正是我想问的问题。我有一张发票,它有多个行项目,加起来存储在NSMutableArray中。如果我将其存储在NSUserDefaults中会发生什么? 这样做好还是不好?行项目可能是1或2,甚至可能是数百个行项目!O.o - Randika Vishman
1
@vishman,我们可以存储那么多的数据,但这从来不是一个好习惯。在应用程序崩溃的情况下,您总是有数据丢失的风险。 - rptwsthi
太棒了!这正是我所想的!谢谢!我猜在像上面提到的任何情况下,我们都应该使用临时表来存储数据,对吧?这是唯一的最佳实践!(CoreData或纯SQLite实现)我的梦想是成为一名优秀的iOS工程师。这就是我开始思考这些问题的地方!欢迎分享你的想法!(y) - Randika Vishman

9

NSUserDefaults 提供了一个非常简单的学习曲线和线程安全的实现。

否则,我发现在各个方面 Core Data 都更优秀。特别是关于配置默认值和迁移例程方面。

编辑:事实证明,NSUserDefaults 的“线程安全性”似乎来自于在主线程上运行操作。这导致我的某个应用程序出现了严重的帧跳过问题;因此我最终删除了 NSUserDefaults,并将其替换为一个线程安全的 NSMutableDictionary,该字典被序列化到文件中。


我能像使用NSUserDefaults一样将Core Data用作字典吗?就是存储键值对吗?我对Core Data并不了解。保存的数据是否可以像plist那样成为分层数据库?有没有好的教程可以教我如何以这种方式保存一些数据? - SEG
1
请查看“用户信息字典”部分 http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreData/Articles/cdMOM.html您可以将NSDictionary序列化为NSData。因此,您可以将NSDictionary保存为实体的属性。http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreData/Articles/cdNSAttributes.html您可以通过仅定义实体和关系来创建分层数据库,其中根级实体没有父级。 - lorean
1
希望我能多次点赞——我的应用程序遭受了几周的偶发性冻结,现在解决方案显而易见!如果数据存储阻塞主线程,那么它究竟是如何“线程安全”的呢?非常误导人。 - Cbas

4

我目前正在进行的一个项目需要设置一个大型数据库(约400,000条记录)。如果你使用NSUserDefaults,你必须添加记录,这可能需要几分钟(取决于设备和数据导入方式)。如果你使用CoreData,你可以简单地将预先构建的数据库复制到应用程序的文档目录中并立即使用它。

这就是为什么我依赖于CoreData。


1

CoreData的一个优点是,您的对象将成为带有属性的NSManagedObject。这意味着当您获取或设置值时,您将具有自动完成以帮助您处理属性名称。这也使代码更易读。

与此同时,使用NSUserDefaults时,您必须始终使用键值访问器,并使用字符串作为键。

I.e.:

myGlobalSettingsObject.lastLoginTime = @(now);

相对于:

[[NSUserDefaults standardUserDefaults] setValue:@(now) forKey:@"lastLoginTime"];

如果你在某个地方意外地打错了键,会怎么样?编译器不会警告你。如果有人在某个地方输入了错误的类型,编译器也不会警告你。

E.g.:

[[NSUserDefaults standardUserDefaults] setValue:@"now" forKey:@"lastLoginTiem"]; ^ ^ ^^^^

这段代码不会在编译时引发任何警告或错误...但是很危险!

使用NSManagedObject的其他好处包括可以进行验证;它可以确保非空值;它可以具有自定义的getter和setter方法,您可以使用这些方法来执行一些酷炫的操作;如果您更改了有关如何存储所有值的方式,它可以处理自动迁移;并且其数据模型成为您的存储库的一部分,因此您可以轻松跟踪对其所做的更改历史记录。

与此同时,NSUserDefaults是快速而简单的,非常适用于基本应用程序,但它只是非常原始。对于小型应用程序来说很好,但如果您有一个庞大的应用程序,与使用Core Data相比,它将变得难以管理。

NSUserDefaults唯一可能的好处就是,如果您的应用程序需要删除其CoreData存储或者您不想费心实现线程安全的CoreData,则在这方面维护较低。


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