Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Which pattern for wrapping NSUserDefaults?

My apps use [NSUserDefaults standardUserDefaults] as a quick and dirty database to store state about the user and the app itself. The trouble with NSUserDefaults is that its flexibility allows for a big mess down the line, for example when different files all set and read different keys in the dictionary in their own way. You don't get to enforce rules, you can screw up the key name etc..

I wrote a simple singleton "manager-style" wrapper for NSUserDefaults which both takes care of setting the default values when used, hides the name of keys used to fetch the values and encapsulates some extra logic, such as encoding to NSData, when storing and retrieving objects from the store.

At this point they're properties backed by a read/set accessor, but something is rubbing me wrong about it and I'm wondering if perhaps there's a more elegant way of achieving the same result. There's quite a bit of boilerplate and the syntax ends up being somewhat unpleasant. To give you an example:

.h:

@interface UserDefaultsManager: NSObject

+ (UserDefaultsManager *)sharedInstance;

@property (nonatomic, assign) NSInteger somethingImTracking;

@end

and .m:

NSString * const kSomethingImTracking= @"SomethingImTracking";

@implementation UserDefaultsManager

[...]

- (NSInteger)somethingImTracking
{
    return [[[NSUserDefaults standardUserDefaults] objectForKey:kSomethingImTracking] intValue];
}

- (void)setSomethingImTracking:(NSInteger)somethingImTracking
{
    [[NSUserDefaults standardUserDefaults] setInteger:somethingImTracking forKey:kSomethingImTracking];
}

and to access:

NSInteger foo = [UserDefaultsManager sharedInstance].somethingImTracking;
like image 392
Alexandr Kurilin Avatar asked Dec 28 '12 04:12

Alexandr Kurilin


1 Answers

Personally I use string constants to store the key names, and just access the user defaults object directly, but I don't tend to use defaults to a huge extent, or in many different classes.

One improvement I'd make to your code is to have them all as class methods instead. There is no benefit to a singleton (you're not maintaining any state, that's all in the defaults object) and this takes a bit of the ugly repetitive code (...sharedInstance) out of your use pattern.

synchronize is not necessary to include every time you set. It is only needed when accessing defaults values from different threads in quick succession. The OS calls it itself periodically as well.

like image 98
jrturton Avatar answered Oct 13 '22 10:10

jrturton