Rikh Rikh - 1 month ago 18
iOS Question

Storing custom objects as NSDictionary vs NSData

I was going through some tutorials regarding storing custom objects in NSUserDefaults. I can't figure out which is the better approach and/or benefits regarding storing your model after converting it back to

NSDictionary
and storing the dictionary vs using
NSKeyedArchiver
to store the object in
NSUserDefaults
. As per my understanding you will have to set the
encodeWithCoder
and
initWithCoder
methods which will enable you set the values for various keys and basically convert everything to
NSData
. Converting the model back to
NSDictionary
will also follow the same steps.

So what are the benefits of using one approach over the other or if one approach may cause something to break anywhere?

Using
NSKeyedArchiver
will do something like:

- (void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:self.test forKey:@"string"];
[encoder encodeObject:self.surname forKey:@"surname"];
}


And converting model back to
NSDictioanry
:

-(NSDictionary *)dictionaryWithModel:(Model *)model{

NSDictionary *dictionary = @{
@"dict":[model.innerModel dictionaryWithModel:model.innerModel],
@"string":self.test
};

return dictionary;
}


Basically which of the would be better when storing object in
NSUserDefaults
?

Answer

Here is my answer on another similar question.

You can set object like this:

NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:savingbean];
[currentDefaults setObject:data forKey:@"DATA"];
[currentDefaults synchronize];

and for get object like this:

NSData *data = [currentDefaults objectForKey:@"DATA"];
SavingBean *token = [NSKeyedUnarchiver unarchiveObjectWithData:data];

For Custom class you have to edit this methods in you bean class:

- (void)encodeWithCoder:(NSCoder *)encoder
{
    [encoder encodeObject:self.userName==nil?@"":self.userName forKey: @"userName"];
    [encoder encodeObject:self.passWord==nil?@"":self.passWord forKey: @"passWord"];
}

-(id)initWithCoder:(NSCoder *)decoder
{
    self = [super init];
    if(self)
    {
        self.userName = [decoder decodeObjectForKey: @"userName"];
        self.passWord = [decoder decodeObjectForKey: @"passWord"];
    }
    return self;
}

Here is most voted similar answer. You can also get good stuff from there.

You can also use JSON Accelerator to create bean class. This is very simple and powerful tool.

EDIT:

The NSUserDefaults class provides convenience methods for accessing common types such as floats, doubles, integers, Booleans, and URLs. A default object must be a property list, that is, an instance of (or for collections a combination of instances of): NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary. If you want to store any other type of object, you should typically archive it to create an instance of NSData.

Values returned from NSUserDefaults are immutable, even if you set a mutable object as the value. For example, if you set a mutable string as the value for "MyStringDefault", the string you later retrieve using stringForKey: will be immutable.

Note: The user defaults system, which you programmatically access through the NSUserDefaults class, uses property lists to store objects representing user preferences. This limitation would seem to exclude many kinds of objects, such as NSColor and NSFont objects, from the user default system. But if objects conform to the NSCoding protocol they can be archived to NSData objects, which are property list–compatible objects. For information on how to do this, see ““Storing NSColor in User Defaults”“; although this article focuses on NSColor objects, the procedure can be applied to any object that can be archived.

https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/nsuserdefaults_Class/Reference/Reference.html

EDIT:

When defining your app’s preferences, it is better to use simple values and data types whenever possible. The preferences system is built around property-list data types such as strings, numbers, and dates. Although you can use an NSData object to store arbitrary objects in preferences, doing so is not recommended in most cases.

Storing objects persistently means that your app has to decode that object at some point. In the case of preferences, a stored object means decoding the object every time you access the preference. It also means that a newer version of your app has to ensure that it is able to decode objects created and written to disk using an earlier version of your app, which is potentially error prone.

A better approach for preferences is to store simple strings and values and use them to create the objects your app needs. Storing simple values means that your app can always access the value. The only thing that changes from release to release is the interpretation of the simple value and the objects your app creates in response.

https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/UserDefaults/AboutPreferenceDomains/AboutPreferenceDomains.html#//apple_ref/doc/uid/10000059i-CH2-SW2