Nickkk
Nickkk

Reputation: 2647

Binding a NSPopupButton's selected identifier

I have several popup buttons whose selected tag is saved in the user defaults (by binding the selected tag in the Bindings inspector). Now instead of saving an integer I would like to save a string value (for the simple reason that it makes the user defaults more "readable" and failsafe), but unfortunately didn't find a way to bind a popup button's selected identifier. Is there a solution to this problem?

Upvotes: 2

Views: 590

Answers (1)

Andrew Madsen
Andrew Madsen

Reputation: 21373

The bindings for NSPopupButton can be a little confusing. The various Content* bindings are used to provide the button with its list of possible selections. Content itself is used to provide a list of objects represented by the items in the pop up button. Content Values is used to provide the actual values displayed in the pop up button. For example, Content might be bound to an array of model objects, while Content Values is bound to a specific key path on those objects, for example name, because you want to display the value of the name property of each item in the popup button itself.

Similarly, the bindings for selection correspond to this system. Selected Object means that when a given item is selected, the underlying full object from the Content array will be selected/set on the bound property, not just the simple displayed string (or number, etc.) value. On the other hand, Selected Value will indeed bind just the displayed value.

Taken together, and in your case, where you're not using the content bindings, this means that you have two options:

  1. Bind the Selected Value to user defaults.
  2. Create an underlying model class with both an identifier property and a name (or whatever you want to call it) property. Bind the Content binding to an array of those objects, and the Content Values binding to thatArray.name.

Option 1

This option is much simpler. Just set up the selected values binding and you're done. It has the major disadvantage that the actual displayed string is the thing being stored in user defaults. This means that if you change the wording of an item, that previously stored selection won't be restored, even if it corresponds directly to the newly-worded item. More importantly, it's not a good idea to make localized -- or potentially localized -- strings semantically important.

Option 2

This takes a little more work (and code), but it would solve your problem in a robust, "correct" way. For example:

@objcMembers class Option: NSObject {
  dynamic var name: String
  dynamic var identifier: String

  init(name: String, identifier: String) {
    self.name = name
    self.identifier = identifier
  }
}

class ViewController: UIViewController {
  @objc dynamic var optionsForPopup = [Option(name: "Item A", identifier: "id 1"),
                                       Option(name: "Item B", identifier: "id 2"),
                                       Option(name: "Item C", identifier: "id 3")]
}

Bind:

  • Content to ViewController - optionsForPopup.
  • Content Values to ViewController - optionsForPopup.name.
  • Selected Value to Shared User Defaults Controller - Controller Key: values, Model Key Path: WhateverUserDefaultsKeyYouWant.

Example

I've created an example project that implements option 2 here: https://github.com/armadsen/PopupDemo

Upvotes: 3

Related Questions