【问题标题】:Save NSMutableArray to NSUserDefaults将 NSMutableArray 保存到 NSUserDefaults
【发布时间】:2013-04-16 16:27:49
【问题描述】:

我正在尝试将数组保存到 NSUserDefaults。 我读到我必须使用编码器和解码器,但我仍然得到同样的错误

*** -[NSUserDefaults setObject:forKey:]: Attempt to insert non-property value '(
    "<Item: 0x1e86e380>",
    "<Item: 0x1e86fd60>",
    "<Item: 0x1e86fda0>",
    "<Item: 0x1e86fde0>",
    "<Item: 0x1e86fe10>"
)' of class '__NSArrayM'.  Note that dictionaries and arrays in property lists must also contain only property values.
[unknown][unknown][unknown][unknown][unknown](gdb) 

为什么?

这是我的代码:

这是我的模特。它有NSStringsNSNumbersNSMutableArrays

- (void)encodeWithCoder:(NSCoder *)encoder
{
    [encoder encodeObject: self.title forKey:@"title"];
    [encoder encodeObject: self.desc forKey:@"desc"];
    [encoder encodeObject: (NSNumber*) self.day forKey:@"day"];
    [encoder encodeObject: self.images forKey:@"images"];
}

- (id)initWithCoder:(NSCoder *)decoder
{
    self = [super init];
    if( self != nil )
    {
        self.title = [decoder decodeObjectForKey: @"title"];
        self.desc = [decoder decodeObjectForKey: @"desc"];
        self.day = [decoder decodeObjectForKey: @"day"];
        self.images = [decoder decodeObjectForKey: @"images"];

    }
    return self;
}

这是在 AppDelegate 的 DidFinishLaunching 方法中:

if([[NSUserDefaults standardUserDefaults] objectForKey:@"savedData"] == nil)
{
    items = [[NSMutableArray alloc] init];

    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"items" ofType:@"json"];
    NSString *contents = [NSString stringWithContentsOfFile: filePath  encoding: NSUTF8StringEncoding error: nil];
    SBJsonParser *jsonParser = [[SBJsonParser alloc] init];
    NSMutableDictionary *json = [jsonParser objectWithString: contents];
    jsonParser = nil;
    items = json[@"item"];

    for(NSDictionary *itemDict in items)
    {

        Item *item = [[Item alloc] init];

        item.title = [itemDict valueForKey:@"title"];
        item.desc = [itemDict valueForKey:@"description"];
        item.day = [itemDict valueForKey:@"day"];
        item.images = [itemDict valueForKey: @"images"];

        [items addObject: item];

    }    
}
else
{

    NSData *decodedObject = [userDefault objectForKey: [NSString stringWithFormat:@"savedData"]];
    NSArray *decodedArray =[NSKeyedUnarchiver unarchiveObjectWithData: decodedObject];


    items = [decodedArray mutableCopy];

}

这是我在AppWillTerminate:

   userDefault = [NSUserDefaults standardUserDefaults];
   NSData *encodedObject = [NSKeyedArchiver archivedDataWithRootObject: items];
   [userDefault setObject: encodedObject forKey:[NSString stringWithFormat:@"savedData"]];

【问题讨论】:

  • 我不认为此异常来自您显示的代码。在 Xcode 中添加异常断点。我怀疑您在项目的其他地方使用setObject:forKey:Items(非属性列表对象)数组。
  • 是的。当我删除该代码时,错误消失了..
  • NSUserDefault中只能存储内置对象类型的值,如果你尝试存储自定义(用户定义的对象)会产生错误,所以请存储内置对象

标签: objective-c nsuserdefaults encoder decoder


【解决方案1】:

前言:了解用户默认值不是通用数据库。除非您建议存储的数据非常小,否则我强烈建议您不要这样做。另一种方法是将数据存储在明确定义的位置,例如应用程序支持目录。

编辑

在上一段中,我已经说过应用程序支持目录不应该用于将更改的数据。我找不到任何支持这一点的东西。苹果自己的文档指出,它是“您的应用程序存储任何类型的文件的地方,该文件支持该应用程序但不是应用程序运行所必需的”,用户数据不应该存储在那里,并且每个应用程序都应该创建和维护自己的目录里面,而不是写到它的顶层。完全不确定我是在哪里捡到这个小说的,很抱歉让它长期存在。

结束编辑

话虽如此,当编译器抱怨“非属性值”时,这意味着您正在尝试编写不是NSArray,NSDictionary,NSString,NSData,@987654325 的东西@或NSNumber.

您是正确的,您自己的对象需要使用 NSKeyedArchiver 和 NSKeyedUnarchiver。但仅仅因为您在模型对象中实现 NSCoding 方法并不会改变它不是属性列表值的事实。

您需要做的是在尝试存储每个对象之前使用NSKeyedArchiver。这会生成一个NSData 的实例,可以将其存储为属性列表对象。

【讨论】:

  • 为什么要避开应用程序支持文件夹?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-03
  • 2013-11-07
相关资源
最近更新 更多