Question

So I have a small value that needs to by synced across my app through NSUserDefaults. I found myself saving and getting the value from NSUserDefaults a bit and I thought it might be nice to link a Getter / Setter directly to NSUserDefaults.

Here's my Getter / Setter code:

- (void) setSomeProperty:(id)someValue {
    [[NSUserDefaults standardUserDefaults]setObject:someValue forKey:@"someProperty"];
}

- (id) someProperty {
    return [[NSUserDefaults standardUserDefaults]objectForKey:@"someProperty"];
}

Here's How I Access:

someClass.someProperty = @"SomeValue"; // -- Set's To @"SomeValue"

id someValue = someClass.someProperty; // -- Assigns Value From NSUserDefaults

This way, when I update or retrieve the property, it is always directly accessing the NSUserDefault Value. To me it seems like a simpler way to write to and retrieve values from my NSUserDefaults, but perhaps there is something problematic or a performance consideration with this that I'm overlooking. Feedback / Concerns are appreciated.

Question

Is this acceptable practice, and will this cause problems later on?

Was it helpful?

Solution

What you're doing is ok, but has some implications that you should be aware of.

NSUserDefaults is disk-based storage. As such is it significantly slower than memory-based solutions. On iOS, "disk-based" means flash memory, which is still significantly slower than memory-based storage.

Flash memory also has a limited number of write cycles before it fails.

For these 2 reasons, I would not use the above technique for values that change rapidly, or where you require fast response.

Also, I'm assuming that since you say "...synced across my app..." you mean shared between multiple objects.

I would suggest making sure to document these properties in your header so it's clear that they are shared, persistent properties. Adding the words "shared" or "saved" to those property names would be a help, in addition to descriptive text in the header.

If your only requirement is shared access, and you don't need persistence, you might look at using a data container singleton instead of using user defaults. (You create a singleton object that has properties that you want to share, and then you fetch a pointer to the singleton from anywhere in your app and use it to read/write the properties that you want to share.)

You could even use a hybrid approach, where you collect these properties in a singleton, and implement persistence in the singleton. This has the advantage of centralizing your save/read logic in one place, so you can change it to use a different storage method if you decide to at some future date.

OTHER TIPS

Personally, I find it much better to just get the defaults in the procedure that you wish to use. So:

NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];

NSString* myValue = [defaults stringForKey:@"mykey"];
//manipulate myValue;

... You can clearly see your intent in the code.

No technical reason not to do it. Some will tell you that a property may signal to other developers that it's a simple getter/setter, and not something that invokes reads from the hard drive or a remote server.

It can depend on the context - perhaps if you name your class in a way that communicates that it's some sort of an object that is tied to storage it will be better. You won't have performance issues unless you use the properties excessively (inside of inner loops, retrieving it multiple times in the calculations instead of using a variable, etc). Otherwise I'd use 2 methods instead with a "load"/"read" and "save"/"write" prefixes to their names so that other developers know they should cache the values and only call them when they need data that is up to date.

Edit: For 99% of the cases, though, you'll be fine doing just what you described. Personally that's what I do, but I think you should be aware of the concerns I described in the answer.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top