NSUserDefaults Boiler Plate Generation

NSUserDefaults boilerplate code made simple.

Creating a category on NSUserDefaults is a pretty common activity, I believe I first saw the technique in iOS Recipes and I’ve done it ever since. By writing a category you can make your use of NSUserDefaults follow how you write code everywhere else using accessors and having the compiler check this for you without messing with string keys.

As a result the standard usage of NSUserDefaults may look something like this

Defaults without properties

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

[defaults setObject:@"remember me" forKey:@"ImportantStuff"];
NSString *importantStuff = [defaults stringForKey:@"ImportantStuff"];

The issue here is that there is a lot of noise in the above code which hides what we are doing - simple assignment and retrieval.

By adding a category we can simplify this

NSUserDefaults+PSProperties.h

@property (nonatomic, copy) NSString *ps_importantStuff;

NSUserDefaults+PSProperties.m

NSString * const PSImportantStuff = @"PSImportantStuff";

...

- (NSString *)ps_importantStuff;
{
  return [self stringForKey:PSImportantStuff];
}

- (void)setPs_importantStuff:(NSString *)importantStuff;
{
  [self setObject:importantStuff forKey:PSImportantStuff];
}

We can now rewrite the first example using this category, which has the nice effect or removing most of the noise and making our intent clearer.

Defaults with properties

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

defaults.ps_importantStuff = @"remember me";
NSString *importantStuff = defaults.ps_importantStuff;

This technique is nice but as you can see it requires a fair amount of boiler plate code and all of this was to just add one property.

##Solution

When reading an issue of iOSDevWeekly I saw the class GVUserDefaults mentioned and this got me intrigued. The class uses some Objective-C mataprogramming to lazily add getters and setters at runtime. It’s worth checking out but it does have some limitations, which got me to thinking how would I do this?

I ended up going a different route and making a Ruby gem that uses a simple DSL to generate the category and add it to your Xcodeproj. It’s just a different approach to the same problem.

The best place to read about how to try my gem out is on the project page here.

You can’t use your system version of Ruby (as it is too old) but rvm or rbenv are pretty easy to set up and then it’s as simple as

gem install defgen

##Features of Defgen

###Conclusion

The process of making this gem was fun but a pretty steep learning curve for me, hopefully if this proves useful I have some other ideas for other things that could do with code generating DSL’s.