Thomson Comer Thomson Comer - 2 months ago 18
Objective-C Question

Why is NSUserDefaults unwilling to save my NSDictionary?

I'm using KVC to serialize an

NSObject
and attempt to save it to
NSUserDefaults
, which is giving me an
Attempt to insert non-property value
when I try to store my
NSDictionary
.

Following are the properties of the object in question,
MyClass
:

@interface MyClass : NSObject
@property (copy,nonatomic) NSNumber* value1;
@property (copy,nonatomic) NSNumber* value2;
@property (copy,nonatomic) NSString* value3;
@property (copy,nonatomic) NSString* value4;
@property (copy,nonatomic) NSString* value5;
@property (copy,nonatomic) NSString* value6;
@property (copy,nonatomic) NSString* value7;
@property (copy,nonatomic) NSString* value8;
@end


When it is time to save MyClass it occurs here:

-(void)saveMyClass
{
NSArray* keys = [NSArray arrayWithObjects:
@"value1",
@"value2",
@"value3",
@"value4",
@"value5",
@"value6",
@"value7",
@"value8",
nil];
NSDictionary* dict = [self dictionaryWithValuesForKeys:keys];
for( id key in [dict allKeys] )
{
NSLog(@"%@ %@",[key class],[[dict objectForKey:key] class]);
}
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:dict forKey:[NSString stringWithString:kMyClassKey]];
[defaults synchronize];
}


which produces this output:

2012-02-23 19:35:27.518 MyApp[10230:40b] __NSCFConstantString __NSCFNumber
2012-02-23 19:35:27.519 MyApp[10230:40b] __NSCFConstantString __NSCFNumber
2012-02-23 19:35:27.519 MyApp[10230:40b] __NSCFConstantString __NSCFString
2012-02-23 19:35:27.519 MyApp[10230:40b] __NSCFConstantString __NSCFString
2012-02-23 19:35:27.520 MyApp[10230:40b] __NSCFConstantString __NSCFString
2012-02-23 19:35:27.520 MyApp[10230:40b] __NSCFConstantString __NSCFString
2012-02-23 19:35:27.520 MyApp[10230:40b] __NSCFConstantString __NSCFString
2012-02-23 19:35:27.520 MyApp[10230:40b] __NSCFConstantString NSNull
2012-02-23 18:38:48.489 MyApp[9709:40b] *** -[NSUserDefaults setObject:forKey:]: Attempt to insert non-property value '{
value1 = "http://www.google.com";
value2 = "MyClassData";
value3 = 8;
value4 = "<null>";
value5 = "http://www.google.com";
value6 = 1;
value7 = "http://www.google.com";
value8 = 4SY8KcTSGeKuKs7s;
}' of class '__NSCFDictionary'. Note that dictionaries and arrays in property lists must also contain only property values.`


As you can see, all of the objects in the
dict
are property list values and all of its keys are
NSString*
. What trivia am I lacking in order to execute this? Or should I give up and use
writeToFile
or similar?

Answer

Props to Kevin who suggested printing the values, of course one of which is of type NSNull which is not a property list value. Thanks!

The kludgy solution to my problem - iterate over the keys of the dictionary I just produced so conveniently with dictionaryWithValuesForKeys and remove those of type NSNull. sigh

NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithDictionary:[self dictionaryWithValuesForKeys:keys]];
for( id key in [dict allKeys] )
{
    if( [[dict valueForKey:key] isKindOfClass:[NSNull class]] )
    {
        // doesn't work - values that are entered will never be removed from NSUserDefaults
        //[dict removeObjectForKey:key];
        [dict setObject@"" forKey:key];
    }
}