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

问题描述:

我想在NSUserDefaults中保存一个NSMutableDictionary对象。 NSMutableDictionary中的密钥类型为NSString,值类型为NSArray,其中包含实现NSCoding的对象列表。根据文件,NSStringNSArray均符合NSCoding为什么NSUserDefaults无法在iPhone SDK中保存NSMutableDictionary?

我收到此错误:

[NSUserDefaults setObject: forKey:]: Attempt to insert non-property value.... of class NSCFDictionary.

这个任何解决方案?

我发现一个替代方案,在保存之前,我使用NSKeyedArchiver编码根对象(NSArray对象),以NSData结尾。然后使用UserDefaults保存NSData

当我需要数据时,我读出NSData,并使用NSKeyedUnarchiverNSData转换回对象。

这是一个有点麻烦,因为我需要每次转换/从NSData,但它只是工作。

这里是每个请求一个例子:

节省:

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 
NSMutableArray *arr = ... ; // set value 
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:arr]; 
[defaults setObject:data forKey:@"theKey"]; 
[defaults synchronize]; 

负载:

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 
NSData *data = [defaults objectForKey:@"theKey"]; 
NSArray *arr = [NSKeyedUnarchiver unarchiveObjectWithData:data]; 

数组中的元素实现

@interface CommentItem : NSObject<NSCoding> { 
    NSString *value; 
} 

然后,在实施的CommentItem,提供了两种方法:

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

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

任何人都有更好的解决方案吗?

谢谢大家。

是字典中的所有密钥NSString s?我认为他们必须为了将字典保存到物业清单。

+1

键是NSString。但值是NSArray,其元素是一个实现NSCoding的定制类。看起来解决方案不工作,因为UserDefaults只支持6种类型,不考虑NSCoding。 – BlueDolphin 2009-01-23 21:11:10

如果要以用户默认值保存对象,则所有对象以递归方式递减,必须是属性列表对象。符合NSCoding并不意味着什么 - NSUserDefaults不会自动将它们编码为NSData,您必须自己做。如果你的“实现NSCoding的对象列表”表示不是属性列表对象的对象,那么在保存为用户默认值之前,你必须对它们做些什么。

供参考的财产清单类NSDictionaryNSArrayNSStringNSDateNSDataNSNumber。你可以写出可变的子类(如NSMutableDictionary)给用户的喜好,但你读出的对象将永远是不可变的。

+60

我还应该提到,如果键是NSStrings,NSDictionary只是一个属性列表对象。一般来说,您可以使用其他对象作为字典键,但在需要属性列表的情况下,键必须是字符串。 – 2009-01-23 04:45:32

+0

我遇到了同样的问题,当我想将NSURL作为对象存储在NSDictionary中并将其存储在NSUserDefaults中时。我不得不将它改成NSString,而不是它的工作。 – NicTesla 2011-10-31 09:46:26

+1

太棒了!在我的情况下,我试图使用NSNumber作为用户默认的NSDictionary的关键。我必须将其更改为NSString。 – Joey 2012-05-25 01:40:09

没有更好的解决方案。另一个选择是将编码的对象保存到磁盘 - 但这是做同样的事情。他们最终都会得到NSData,当你想要它时,它会被解码。

您是否考虑过在实施NSCoding协议?这将允许您使用两种简单的方法在iPhone上进行编码和解码,这些方法使用NSCoding实现。首先,您需要将NSCoding添加到您的课程中。

下面是一个例子:

这是.h文件

@interface GameContent : NSObject <NSCoding> 

然后,你将需要实现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"]; 
    } 

查看关于NSCoder的文档以获取更多信息。对于我需要在应用程序关闭时将应用程序的状态保存在iPhone中的项目,并在返回时将其恢复到它的状态,这对于我的项目非常有用。

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

我希望这有助于!

简单的答案:

NSDictionary只是的plist对象,如果键NSString的。 因此,将“钥匙”作为NSStringstringWithFormat


解决方案:

NSString *key = [NSString stringWithFormat:@"%@",[dictionary valueForKey:@"Key"]]; 

优点:

  1. 这将增加字串值
  2. 当您的变量值为NULL时,它将添加空值