【问题标题】:How to serialize a NSDictionary/NSArray/Property List (plist) which contains NSNull如何序列化包含 NSNull 的 NSDictionary/NSArray/Property List (plist)
【发布时间】:2009-08-07 11:22:40
【问题描述】:

我想使用NSNull 将一些空值存储在NSMutableDictionary 中,然后使用属性列表序列化这些数据。问题是 NSNull 是不允许的,我得到“属性列表格式无效”错误。有解决方法吗?他们没有将NSNull 放在有效的 plist 对象列表中,这似乎很令人惊讶。

【问题讨论】:

  • Saurabh Wadhwa 提供的答案效果很好,我自己也用过,可惜原帖不在身边接受...

标签: ios objective-c cocoa serialization


【解决方案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,也不打算扩展。

以下是相关文档的链接:NSCodingNSKeyedArchiverNSKeyedUnarchiver

【讨论】:

    【解决方案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 支持!= 序列化。
    猜你喜欢
    • 1970-01-01
    • 2011-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-09
    • 2011-01-08
    相关资源
    最近更新 更多