如何序列化包含 NSNull 的 NSDictionary/NSArray/Property List (plist)
Posted
技术标签:
【中文标题】如何序列化包含 NSNull 的 NSDictionary/NSArray/Property List (plist)【英文标题】:How to serialize a NSDictionary/NSArray/Property List (plist) which contains NSNull 【发布时间】:2009-08-07 11:22:40 【问题描述】:我想使用NSNull
将一些空值存储在NSMutableDictionary
中,然后使用属性列表序列化这些数据。问题是 NSNull
是不允许的,我得到“属性列表格式无效”错误。有解决方法吗?他们没有将NSNull
放在有效的 plist 对象列表中,这似乎很令人惊讶。
【问题讨论】:
Saurabh Wadhwa 提供的答案效果很好,我自己也用过,可惜原帖不在身边接受... 【参考方案1】:我在序列化之前将 NSArray 或 NSDictionary 转换为 NSData。以下是用于序列化和反序列化的 nsarray 类别。这很舒服,可以处理一些 nsnull 的数据
@implementation NSArray(Plist)
-(BOOL)writeToPlistFile:(NSString*)filename
NSData * data = [NSKeyedArchiver archivedDataWithRootObject:self];
NSArray * paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString * documentsDirectory = [paths objectAtIndex:0];
NSString * path = [documentsDirectory stringByAppendingPathComponent:filename];
BOOL didWriteSuccessfull = [data writeToFile:path atomically:YES];
return didWriteSuccessfull;
+(NSArray*)readFromPlistFile:(NSString*)filename
NSArray * paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString * documentsDirectory = [paths objectAtIndex:0];
NSString * path = [documentsDirectory stringByAppendingPathComponent:filename];
NSData * data = [NSData dataWithContentsOfFile:path];
return [NSKeyedUnarchiver unarchiveObjectWithData:data];
【讨论】:
非常好!当键控存档器中更常见的方法不起作用时,这很有效(我刚刚验证过)。【参考方案2】:考虑使用 NSKeyedArchiver 和 NSKeyedUnarchiver,而不是使用属性列表。属性列表有一组固定的类型,不包括 NSNull,也不打算扩展。
以下是相关文档的链接:NSCoding、NSKeyedArchiver 和 NSKeyedUnarchiver。
【讨论】:
【参考方案3】:不,没有办法将NSNull
放在属性列表中。 (花絮:二进制属性列表格式其实支持空值,但是作者没有实现支持。)
对于字典,最简单的解决方法是简单地过滤掉空值,所以 foo = "bar";巴兹=空; 变成 foo = "bar"; 。
【讨论】:
它与我需要空值来指示密钥存在但没有对应值的情况并不完全相同(即我已经知道有一个没有数据的密钥而不是它的新密钥我不知道)。 也许您可以同时序列化 A)仅包含具有相应值的键的字典和 B)所有已知键的数组,无论它们是否附加了数据。最终没有办法将 NSNull 直接放在 plist 中,因此您需要找到解决方法。【参考方案4】:来自 NSPropertyListSerializationClass 的文档:
一个属性列表对象。 plist 必须是 一种 NSData, NSString, NSNumber, NSDate、NSArray 或 NSDictionary 目的。容器对象也必须 仅包含这些类型的对象。
所以你需要其中之一。根据数据的类型,您可以放入占位符而不是 NSNull,然后在加载 .plist 之前/之后执行一个过程(例如,使用长度为零的 NSData 对象在 plist 中表示您的 NSNull)。究竟什么样的占位符将取决于你存储什么样的数据,以及选择要避免的东西。然后,加载后,将空的 NSData 转换回 NSNull。
【讨论】:
苹果程序员真的有什么问题???我讨厌写这样的代码。 DD,如果你想要的是通用序列化,使用 NSCoder。属性列表有一组固定的类型,所以无论它扩展多远,总是需要转换一些东西。 如果您不喜欢属性列表的限制(如文档所示,它不支持 NSNull),请不要使用属性列表。正如其他评论者所建议的那样,使用您自己的序列化格式。 NSPropertyList 支持!= 序列化。以上是关于如何序列化包含 NSNull 的 NSDictionary/NSArray/Property List (plist)的主要内容,如果未能解决你的问题,请参考以下文章
如何在 iOS react-native-config 和 AsyncStorage 中修复 NSNull 类型的 JSON 值“<null>”无法转换为 NSString?
Parse - Swift 中的 NSNull null 模拟
iOS 8 工作但 iOS 7 崩溃 -[NSNull 长度]: unrecognized selector sent to instance