views:

473

answers:

4

I'm subclassing NSUserDefaults in my application. A side effect of this is I can't use [NSUserDefaults sharedUserDefaults], I have to have a class method to provide my own static defaults object. This isn't been a problem in code, but it's proving tricky now that I'm hooking up the preferences UI with bindings.

The shared NSUserDefaultsController uses the shared defaults, so that's out. Instead I can create my own defaults controller in my window controller, provide it with my static defaults object, and hook up my bindings to that. This doesn't fully work though. When I tried using KVO on my defaults object I didn't receive any change notifications. I tried this again with a regular NSUserDefaults object (not a subclass) and again, no KVO notifications. Substituting in the shared defaults object, KVO works exactly how I'd expect.

Does anyone have any ideas on how I can get bindings and KVO to work when I'm not using the shared defaults?

+1  A: 

The documentation provides the answer, I think. The init method initializes a new instance, but doesn't put anything in the search path. If you're initializing your own instances, you'll need to set up the domains you intend to use by hand. My guess would be that your application isn't working because the values that you're trying to get/set don't exist because there are no domains to save them in.

In particular, look at the addSuiteNamed: method and the NSUserDefaultsDomain constants. You'll need to set these up by hand to make your subclass, or any instance of NSUserDefaults other than standardUserDefaults, work properly.

Alex
The documentation is a little confusing on the subject, but it does say init adds the application and registration domains. I've also noticed an init'ed object includes the global domain in 10.5, but not 10.4, so chances are the docs may be slightly outdated too.Anyway, the problem is limited to KVO- my subclassed object saves and reads prefs okay when used in code, so unless I'm missing something it doesn't seem like there are any problems with the search domains. Thanks for the reply though!
Marc Charbonneau
A: 

Since I haven't found a solution yet, I decided to take some advice given to me during the last CocoaHeads Syracuse meeting and switch to using categories instead of subclassing NSUserDefaults. Not a perfect solution, but it'll let me get past this problem and back to work.

Marc Charbonneau
+1  A: 
e.James
+1  A: 

I've been doing something similar just recently, and I'm having pretty good luck so far. I create a standard NSObject subclass (MYUserDefaults for argument). It has properties for the things I want (host, username, etc.) Some go to NSUserDefaults, some go to keychain or the like. It has a standard +sharedUserDefaults singleton method. (*)

In the window owner (NSWindowController or AppDelegate), I provide a -sharedUserDefaults. I then bind through that to the settings I want with a simple keypath (sharedUserDefaults.host). I typically avoid keypaths in bindings because they often obfuscate things, but here I think it keeps everything clear while taking care of the special case that the NIB needs to be prevented from creating an extra non-singleton version.

(*) No fancy "forced singleton" stuff (which might also fix your problem). Am I the only one who thinks Apple should have big flashing "don't use this unless you know why you need it, and then don't use it anyway" sign on this doc? I find that code dangerous to let inexperienced developers see. Half the objects in the last project I worked on had +allocWithZone: overloaded. To me it's just bad form to call +alloc, and get pointers to existing objects. Don't lie to me unless it's absolutely necessary.

Rob Napier