专栏名称: 知识小集
目录
相关文章推荐
纪念币预约信息  ·  开始预约!一二五分纸币!10张9.9包邮! ·  4 小时前  
纪念币预约信息  ·  开始预约!国色天香彩色银币,龙头币! ·  3 天前  
纪念币预约信息  ·  下一站!马年纪念币、马年纪念钞! ·  3 天前  
纪念币发行信息  ·  重磅!2025新版100元纸钞发行!开始预约! ·  3 天前  
纪念币发行信息  ·  重磅!2025新版100元纸钞发行!开始预约! ·  3 天前  
51好读  ›  专栏  ›  知识小集

使用 NSUserDefaults 存储字典的一个坑

知识小集  · 掘金  ·  · 2018-04-24 11:55

正文

使用 NSUserDefaults 存储字典的一个坑

前些时间,@Vong 同学在我们知识小集群里发了一段用 NSUserDefaults 存储一个 NSDictionary 字典对象的测试代码,虽然代码看起来似乎很正常,但是运行的时候报错了,根据群里大家的讨论结果,本文整理总结一下。

问题

我们先来看一下这段测试代码:

- (void)test {
    NSDictionary *dict = @{@1: @"甲",
                           @2: @"乙",
                           @3: @"丙",
                           @4: @"丁"};
    
    [[NSUserDefaults standardUserDefaults] setObject:dict forKey:@"testKey"];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

上述代码先构建了一个 dict 字典对象,然后把它往 NSUserDefaults 里存储,看起来似乎没什么毛病,但在 Xcode 中运行的时候,却报如下错误:

[User Defaults] Attempt to set a non-property-list object {
    3 = "\U4e19";
    2 = "\U4e59";
    1 = "\U7532";
    4 = "\U4e01";
} as an NSUserDefaults/CFPreferences value for key `testKey`

难道是因为上述 NSDictionary 对象的 Key NSNumber 的问题? NSDictionary Key 一定要为 NSString 吗?显然不是的,我们在上述代码的 dict 初始化后打个断点,然后在命令行里 po dict ,是可以正确看到控制台输出 dict 对象的内容。再来看一下 NSDictionary 的定义:

@interface NSDictionary<KeyType, ObjectType> (NSDictionaryCreation)

- (instancetype)initWithObjects:(NSArray<ObjectType> *)objects forKeys:(NSArray<id<NSCopying>> *)keys;

...

@end

我们可以知道, NSDictionary Key 只要是遵循 NSCopying 协议的就行,显然 NSNumber 是遵循的(可自行查看 NSNumber 的定义),因此用 NSNumber 作为 NSDictionary Key 是没问题的。

但是,当我们把上述 dict Key 改为字符串的形式(注意跟上面的区别),如下:

NSDictionary *dict = @{@"甲": @1,
                       @"乙": @2,
                       @"丙": @3,
                       @"丁": @4};

此时, dict 是可以正常存储到 NSUserDefaults 中的。

所以,问题确实是出在 dict Key 上,但到底是什么原因呢?

原因分析

我们需要从 NSUserDefaults setObject:forKey: 方法入手分析:

- (void)setObject:(id)value forKey:(NSString *)defaultName;

通过查看苹果文档:https://developer.apple.com/documentation/foundation/nsuserdefaults/1414067-setobject?language=objc ,有这么一段描述:

The value parameter can be only property list objects: NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary. For NSArray and NSDictionary objects, their contents must be property list objects.

也就是说,能往 NSUserDefaults 里存储的对象只能是 property list objects ,包括 NSData , NSString , NSNumber , NSDate , NSArray , NSDictionary ,且对于 NSArray NSDictionary 这两个容器对象,它们所包含的内容也必需是 property list objects







请到「今天看啥」查看全文


推荐文章
纪念币预约信息  ·  开始预约!一二五分纸币!10张9.9包邮!
4 小时前
纪念币预约信息  ·  开始预约!国色天香彩色银币,龙头币!
3 天前
纪念币预约信息  ·  下一站!马年纪念币、马年纪念钞!
3 天前
纪念币发行信息  ·  重磅!2025新版100元纸钞发行!开始预约!
3 天前
纪念币发行信息  ·  重磅!2025新版100元纸钞发行!开始预约!
3 天前
治愈系心理学  ·  30本名著,浓缩成给女人的30句话
7 年前
冲蒌老伍  ·  陈冠希串爆女记者: 我就系閪人!
7 年前
解放军报  ·  起床号!新闻早报告〔2017.06.18〕
7 年前
雷峰网  ·  入侵保险业,聊天机器人有招?
7 年前