سؤال

I'm trying to save an array to NSUserDefaults. I read that i have to use a encoder and decoder, but i still get the same error

*** -[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) 

Why??

Here's my code:

This is my Model. It has NSStrings, NSNumbers and NSMutableArrays:

- (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;
}

This is in AppDelegate's DidFinishLaunching method:

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];

}

And this i have in AppWillTerminate:

   userDefault = [NSUserDefaults standardUserDefaults];
   NSData *encodedObject = [NSKeyedArchiver archivedDataWithRootObject: items];
   [userDefault setObject: encodedObject forKey:[NSString stringWithFormat:@"savedData"]];
هل كانت مفيدة؟

المحلول

A foreword: Understand that user defaults are not a general-purpose database. Unless the data you propose to store there is quite small, I strongly discourage you from doing this. An alternative is to store the data in a well-defined location, such as the Application Support directory.

EDIT

In the previous paragraph, I had stated that the Application Support directory should not be used for data that will change. I cannot find anything to support this. Apple's own documentation states that it is "where your app stores any type of file that supports the app but is not required for the app to run," that user data should not be stored there, and that each app should create and maintain its own directory inside it, rather than write to its top level. Not at all certain where I picked up this bit of fiction, and am sorry for having perpetuated it.

END EDIT

That being said, when the compiler complains of "non-property value(s)," that means that you're attempting to write something that is not a NSArray, NSDictionary, NSString, NSData, NSDate or NSNumber.

You are correct that your own objects need to make use of NSKeyedArchiver and NSKeyedUnarchiver. But just because you're implementing your NSCoding methods in your model object doesn't change the fact that it's not a property list value.

What you need to do is to use NSKeyedArchiver before you attempt to store each of your objects. This produces an instance of NSData that can be stored as a property list object.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top