Why NSUserDefaults failed to save NSMutableDictionary in iOS?
If you're saving an object in user defaults, all objects, recursively, all the way down, must be property list objects. Conforming to NSCoding doesn't mean anything here-- NSUserDefaults
won't automatically encode them into NSData
, you have to do that yourself. If your "list of object which implements NSCoding
" means objects that are not property list objects, then you'll have to do something with them before saving to user defaults.
FYI the property list classes are NSDictionary
, NSArray
, NSString
, NSDate
, NSData
, and NSNumber
. You can write mutable subclasses (like NSMutableDictionary
) to user preferences but the objects you read out will always be immutable.
Simplest Answer :
NSDictionary
is only a plist object , if the keys are NSStrings.
So, Store the "Key" as NSString
with stringWithFormat
.
Solution :
NSString *key = [NSString stringWithFormat:@"%@",[dictionary valueForKey:@"Key"]];
Benefits :
- It will add String-Value.
- It will add Empty-Value when your Value of Variable is
NULL
.
Are all of your keys in the dictionary NSString
s? I think they have to be in order to save the dictionary to a property list.
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<NSCoding> {
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.