2

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 encodeWithCoderand 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?

Edit: So according to the doc linked in the answer, we should use NSDictionary to store objects in NSUserDefaults (better performance), then why does apple recommend using NSKeyedArchiver?

Rikh
  • 4,078
  • 3
  • 15
  • 35
  • Have a look at my lib: https://github.com/alexburtnik/SettingsBox It allows you to save custom objects as well as all common Foundation objects and primitives to NSUserDefaults in just few lines of code. – alexburtnik Oct 22 '16 at 06:45

1 Answers1

0

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

Community
  • 1
  • 1
Jayesh Thanki
  • 2,037
  • 2
  • 23
  • 32
  • Oops i just added an example! What i wanted to know which is better. Not how to do it! – Rikh Oct 22 '16 at 06:42
  • i think `NSKeyedArchiver` is more suitable way to store custom object in `NSUserDefaults`. – Jayesh Thanki Oct 22 '16 at 06:45
  • But why is that? Can you please add some example or some reason of how it is more optimized? – Rikh Oct 22 '16 at 06:46
  • @Rikh, I have edited my answer, if you have to store custom object in `NSUserDefaults` then you have to use `NSKeyedArchiver` otherwise you can directly use `setObject:` method to store `NSData`, `NSString`, `NSNumber`, `NSDate`, `NSArray`, or `NSDictionary` in `NSUserDefaults`. – Jayesh Thanki Oct 22 '16 at 07:08
  • I understand that. What i wish to know is **which** practice is more optimized/preferred and why? Converting custom object to `NSData` using `NSKeyedArchiver` and then storing in `NSUserDefaults`or converting object to `NSDictionary`and then storing it in `NSUserDefaults` – Rikh Oct 22 '16 at 07:11
  • So basically there is no possible scenario for which `NSKeyedArchiver`would be better for storing values in `NSUserDefaults`? – Rikh Oct 22 '16 at 07:43