为什么NSUserDefaults无法在iOS中保存NSMutableDictionary?

Blu*_*hin 145 cocoa-touch objective-c nsuserdefaults nscoding ios

我想保存一个NSMutableDictionary对象NSUserDefaults.键类型NSMutableDictionaryNSString,值类型是NSArray,它包含实现的对象列表NSCoding.每份文件,NSStringNSArray两者都符合NSCoding.

我收到此错误:

[NSUserDefaults setObject:forKey:]:尝试插入类NSCFDictionary的非属性值....

Blu*_*hin 230

我发现了一个替代方案中,前保存,我编码根对象(NSArray使用对象)NSKeyedArchiver,它与端部NSData.然后使用UserDefaults保存NSData.

当我需要数据时,我读出了NSData,然后NSKeyedUnarchiver用来转换NSData回对象.

这有点麻烦,因为我需要NSData每次都进行转换,但它只是有效.

以下是每个请求的一个示例:

保存:

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *arr = ... ; // set value
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:arr];
[defaults setObject:data forKey:@"theKey"];
[defaults synchronize];
Run Code Online (Sandbox Code Playgroud)

加载:

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *data = [defaults objectForKey:@"theKey"];
NSArray *arr = [NSKeyedUnarchiver unarchiveObjectWithData:data];
Run Code Online (Sandbox Code Playgroud)

数组中的元素实现

@interface CommentItem : NSObject<NSCoding> {
    NSString *value;
}
Run Code Online (Sandbox Code Playgroud)

然后在执行中CommentItem,提供了两种方法:

-(void)encodeWithCoder:(NSCoder *)encoder
{
    [encoder encodeObject:value forKey:@"Value"];
}

-(id)initWithCoder:(NSCoder *)decoder
{
    self.value = [decoder decodeObjectForKey:@"Value"];
    return self;
}
Run Code Online (Sandbox Code Playgroud)

谁有更好的解决方案?

感谢大家.

  • 我们可能需要添加[defaults synchronize]进行保存 (7认同)
  • 你有一个可以分享的代码示例,我一直试图在帖子(537044)中这样做,但没有快乐 (4认同)

Tom*_*ton 105

如果要在用户默认值中保存对象,则所有对象(递归地,一直向下)必须是属性列表对象.符合NSCoding并不意味着什么 - NSUserDefaults不会自动编码NSData,你必须自己做.如果您的"实现的对象列表NSCoding"表示不是属性列表对象的对象,那么在保存到用户默认值之前,您必须对它们执行某些操作.

FYI财产清单类NSDictionary,NSArray,NSString,NSDate,NSData,和NSNumber.您可以将可变子类(如NSMutableDictionary)写入用户首选项,但您读出的对象将始终是不可变的.

  • 我还要提一下,如果键是NSStrings,NSDictionary只是一个属性列表对象.通常,您可以将其他对象用作字典键,但在需要属性列表的情况下,键必须是字符串. (61认同)

Sop*_*ert 14

字典中NSString的所有键都是?我认为他们必须将字典保存到属性列表中.


Bha*_*vin 7

最简单的答案:

NSDictionary如果键是NSStrings,则只是一个plist对象.因此,存储的"钥匙"为用.NSStringstringWithFormat


方案:

NSString *key = [NSString stringWithFormat:@"%@",[dictionary valueForKey:@"Key"]];
Run Code Online (Sandbox Code Playgroud)

好处:

  1. 它将添加String-Value.
  2. 当您的变量值为时,它将添加空值NULL.

  • 我有一个类似的问题:我的密钥是NSNumbers,显然不允许在plist词典的键中. (2认同)

Nie*_*sen 5

您是否考虑过实施该NSCoding协议?这将允许你编码,并与该实现的两个简单的方法对iPhone进行解码NSCoding.首先,您需要将其添加NSCoding到您的班级.

这是一个例子:

这是在.h文件中

@interface GameContent : NSObject <NSCoding>
Run Code Online (Sandbox Code Playgroud)

然后,你将需要实现NSCoding协议的两种方法.

    - (id) initWithCoder: (NSCoder *)coder
    {
        if (self = [super init])
        {
               [self setFoundHotSpots:[coder decodeObjectForKey:@"foundHotSpots"]];
        }
        return self;
    }

    - (void) encodeWithCoder: (NSCoder *)coder
    {
           [coder encodeObject:foundHotSpots forKey:@"foundHotSpots"];
    }
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请查看NSCoder上的文档.这对我的项目非常方便,如果应用程序关闭,我需要在iPhone上保存应用程序的状态,并在重新启动时将其恢复到状态.

关键是将协议添加到接口,然后实现属于的两个方法NSCoding.

我希望这有帮助!