Why is NSUserDefaults unwilling to save my NSDictionary?

白昼怎懂夜的黑 提交于 2019-11-29 03:41:55

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

I usually archive and unarchive dictionaries when saving them to the user defaults. This way you don't have to manually check for NSNull values.

Just add the following two methods to your code. Potentially in a category.

- (BOOL)archive:(NSDictionary *)dict withKey:(NSString *)key {
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSData *data = nil;
    if (dict) {
        data = [NSKeyedArchiver archivedDataWithRootObject:dict];
    }
    [defaults setObject:data forKey:key];
    return [defaults synchronize];
}

- (NSDictionary *)unarchiveForKey:(NSString *)key {
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSData *data = [defaults objectForKey:key];
    NSDictionary *userDict = nil;
    if (data) {
        userDict = [NSKeyedUnarchiver unarchiveObjectWithData:data];
    }
    return userDict;
}

Then you can archive any dictionary like this (assuming the method are available in the class):

NSDictionary *dict = ...;
[self archive:dict withKey:@"a key of your choice"];

and retrieve it later on again like this:

NSDictionary *dict = [self unarchiveForKey:@"a key of your choice"];
Berk

If you need to store;

  • data from a custom object,
  • or an array of custom objects

you can use NSKeyedArchiver methods. You can check leviathan's answer for this method.


However, if you are trying to store;

  • a dictionary that contains either NSString or NSNumber (like a dictionary converted from a JSON service response),
  • or array of this kind of dictionary

you don't need to use NSKeyedArchiver. You can use user defaults.


In my case, when I retrieve the dictionary from user defaults it was returning nil, so I thought NSUserDefaults is unwilling to save my dictionary.

However, it was saved, but I was using the wrong getter method to retrieve it from user defaults;

[[NSUserDefaults standardUserDefaults] stringForKey:<my_key>]

Please make sure you used either;

[[NSUserDefaults standardUserDefaults] dictionaryForKey:<my_key>]

or;

[[NSUserDefaults standardUserDefaults] objectForKey:<my_key>]

before checking any other possible reason.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!