Why Nsuserdefaults Failed to Save Nsmutabledictionary in Ios

Why NSUserDefaults failed to save NSMutableDictionary in iOS?

I found out one alternative, before save, I encode the root object (NSArray object) using NSKeyedArchiver, which ends with NSData. Then use UserDefaults save the NSData.

When I need the data, I read out the NSData, and use NSKeyedUnarchiver to convert NSData back to the object.

It is a little cumbersome, because i need to convert to/from NSData everytime, but it just works.

Here is one example per request:

Save:

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

Load:

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

The element in the array implements

@interface CommentItem : NSObject {
NSString *value;
}

Then in the implementation of CommentItem, provides two methods:

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

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

Anyone has better solution?

Thanks everyone.

Why does NSUserDefaults fail to save NSMutableDictionary?

From Apple's documentation for NSUserDefaults objectForKey:

The returned object is immutable, even if the value you originally set was mutable.

The line:

dictionary = [NSKeyedUnarchiver unarchiveObjectWithData:data];

discards the previously created NSMutableDictionary and returns a NSDictionary.

Change the loading to:

NSData *data = [[NSUserDefaults standardUserDefaults]objectForKey:@"Key"];
dictionary = [NSKeyedUnarchiver unarchiveObjectWithData:data];

Complete example, there is also no need to use NSKeyedArchiver in this example:

NSDictionary *firstDictionary = @{@"Key 4":@4};
[[NSUserDefaults standardUserDefaults] setObject:firstDictionary forKey:@"Key"];

NSMutableDictionary *dictionary = [[[NSUserDefaults standardUserDefaults] objectForKey:@"Key"] mutableCopy];

dictionary[@"Key 1"] = @0;
dictionary[@"Key 2"] = @1;
dictionary[@"Key 3"] = @2;

for (NSString * key in [dictionary allKeys]) {
NSLog(@"key: %@, value: %@", key, [dictionary objectForKey:key]);
}

NSLog output:

key: Key 2, value: 1

key: Key 1, value: 0

key: Key 4, value: 4

key: Key 3, value: 2

Why can't I store NSDictionary in NSUserDefaults?

NSDictionary is a property list object. But in order to store a dictionary, all keys must be NSString and all values must also be property list objects.

Your dictionary contains a non-property list object for the key profile_image since its value is NSNull.

Remove that value from the dictionary and your code should work. Of course your code that loads the dictionary back must deal with the possibility that the key won't be there indicating that it was "null".

Since you are working with NSJSONSerialization, it's possible you could have several NSNull values in the resulting data. You need to recursively find and remove any and all NSNull values.

Why is NSUserDefaults unwilling to save my NSDictionary?

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

NSUserDefaults fail to save NSMutableDictionary

There are very specific restrictions as to what type of data can be synced to NSUserDefaults within an NSDictionary. These include NSString, NSNumber, NSData, NSArray and NSDictionary. Use your NSCoder methods to serialize to NSData (using NSKeyedArchiver) before storing in the NSUserDefaults.

Also, take a look at this

iPhone: Not able to store NSMutableDictionary to NSUserDefaults

You will need to implement this for the elements in your dictionary:

The element in the dictionary implements

@interface CommentItem : NSObject {
NSString *value;
}

Then in the implementation of CommentItem, provides two methods:

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

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

As suggested on the link @Irene provided.

NSMutableDictionary and NSUserDefaults

Of course, only the last valeur is save, as you don't load the previous value in weightLog before adding the new one ! Also one more things, you should change the key for each value.

Try to use this (the date will include year + month + day + hour + minute + second, so don't click more than 1 time per second ;-D ) :

NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];

NSMutableDictionary *weightLog = [NSMutableDictionary dictionaryWithDictionary:[userDefaults objectForKey:@"Weightlog"]];


NSString *date = [NSDateFormatter localizedStringFromDate:[NSDate date]
dateStyle:NSDateFormatterShortStyle
timeStyle:NSDateFormatterFullStyle];

[weightLog setObject:self.weightInput.text forKey:date];

NSLog(@"neweight you entered is %@", self.weightInput.text);
NSLog(@"weightlog is %@", weightLog);

[userDefaults setObject:weightLog forKey:@"Weightlog"];
[userDefaults synchronize];


Related Topics



Leave a reply



Submit