6

How do I bind NSDictionary objects to several text fields in Interface Builder?

I would like to bind each object to a specific item in the dictionary. For example, the first text field should be bound to Actor:

enter image description here

aneuryzm
  • 63,052
  • 100
  • 273
  • 488
  • It's ridiculous 8 years later, but please check the answers, the accepted one ist wrong, but the one from @keeluu is correct. Cheers :9 – Julian F. Weinert Nov 30 '19 at 00:57

3 Answers3

5

You need to add a NSObjectController in Interface Builder. In the attributes inspector tab leave the standard mode "Class" and class name on "NSMutableDictionary", but switch "Prepares Content" on. In the bindings inspector bind "Content Object" to "Shared User Defaults Controller", controller key "values" and "Model Key Path" to your dictionary's key in User Defaults. Switch "Handles Content As Compound Value" on.

Now you can bind your text field (or check boxes etc). values to the ObjectController, with controller key "selection" (!) and the keys in your dictionary (as model key path).

Hope this helps. I couldn't find the answer in Apple's documentation and also not in the net, was lucky to find it out myself by trying different controller objects...

keeluu
  • 116
  • 2
  • 5
  • Just gave this a whirl. It works in the sense that values FROM user defaults are correctly loaded into the UI. But when those values are changed, those changes are not propagated back to user defaults as I would expect. Any idea why? – Bryan Jul 15 '15 at 05:32
  • Figured it out. Added an answer below to elaborate. – Bryan Jul 16 '15 at 01:34
2

First: @keeluu's answer should be marked correct.

Doing it Programmatically

If you're doing this in code rather than through IB, there's a "gotcha" to look out for. It looks like this:

// Assume 'anObjectController' is an NSObjectController.
// Assume 'userDefaultsController' is [NSUserDefaultsController sharedUserDefaultsController]
// Assume 'someDictionary' is an NSDictionary in userDefaults. 

[self.anObjectController 
    bind:NSContentBinding 
    toObject:userDefaultsController 
    withKeyPath:@"values.someDictionary"
    options:@{NSHandlesContentAsCompoundValueBindingOption: @YES}];

If you do the above, you'll find that when you bind your UI elements to properties in someDictionary, those UI elements will correctly display the values that are IN user defaults, but when you change them (by say, clicking a bound checkbox) those values will NOT be updated in user defaults; the old values stick around.

The Reason

The binding must be to NSContentObjectBinding instead of NSContentBinding. The NSObjectController class exposes a binding named contentObject. When you bind to that, everything works properly.

This is an easy mistake to make because Xcode's code completion automatically goes for NSContentBinding and it's one of the most frequently used binding names anyway. This just cost me hours of trouble, so hopefully I saved someone else some time.

Bryan
  • 4,628
  • 3
  • 36
  • 62
  • any idea how you can bind to a nested dictionary? for example this doesn't work: [myButton bind:@"value" toObject:self. anObjectController withKeyPath:@"selection.key1.key2" options:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:@"NSContinuouslyUpdatesValue"]]; It works fine when i use @"selection.key1" as the keyPath. but i need to drill down deeper into the dictionary. – gypsyDev Aug 23 '15 at 13:08
  • 1
    You'd need a nested set of objectControllers. One for each level. – Bryan Sep 02 '15 at 02:20
-1

Try to add NSDictionaryController to you .xib file, then bind its Controller Content to your dictionary in User Defaults. Then you can bind text field values to Dictionary Controller (arrangedObjects key).

I never tried that but I think it must work.

Hope, it helps.

Lloyd18
  • 1,679
  • 1
  • 18
  • 28
  • ya, this is exactly what I'm trying now. However I need to bind a specific item of the NSDictionary to a different Textfield. So I was wondering if I should use the Model key path, beside the ControllerKey = "Arranged Objects" as you suggest. thanks – aneuryzm Nov 10 '11 at 14:48
  • So far I've tried this but it doesn't work. But I guess that the model key path is not the name of an item stored in the NSDictionary. – aneuryzm Nov 10 '11 at 14:50