How do I actually employ comboBoxSelectionDidChange to trigger a change elsewhere in the application?

So, the story is this: I'm pretty new at this, but I have managed to set up a core data model, and to enable the user to create new managed objects dynamically--fill in two NSTextFields and click "add new", basically. Then, I have an NSComboBox that updates its options as new managed objects are added, and displays the appropriate "Name" attribute value in its index. Great.


Now, when I make a selection from that list, I need to display the other attribute value, also a String, in a nearby NSTextField.


I'm almost certain that this involves the NSComboBoxDelegate's function comboBoxSelectionDidChange(notification) but I can't find anything that informs me about how to actually use that to instigate this change in the TextField.


Am I looking in the wrong place? I'm just as happy to be pointed at a good resource as to be told the answer, I'm trying to learn how this all works.

If you're using Core Data, then look at the changes that are occuring to the data source as items are added to it, for example if using fetch request controllers may be look at the notfications from the associated fetch request controllers to drive the changes of the UI to reload the data source of the combo box as the datasource of the fetech request controller changes.


Yes using the comboxSelectionDidChange notification is correct:


import Cocoa
class ViewController: NSViewController {
    @IBOutlet weak var optionsBox: NSComboBox!
    @IBOutlet weak var selectedFruit: NSTextField!

    private let datasource = ["Apples","Cherries"]

    override func viewDidLoad() {
        super.viewDidLoad()
        /
        optionsBox?.dataSource = self
        optionsBox?.delegate = self
    }
    override var representedObject: Any? {
        didSet {
        /
        }
    }
}
extension ViewController: NSComboBoxDataSource {

    func numberOfItems(in comboBox: NSComboBox) -> Int {
        return datasource.count
    }

    func comboBox(_ comboBox: NSComboBox, objectValueForItemAt index: Int) -> Any? {
     
        return datasource[index]
    }



}
extension ViewController: NSComboBoxDelegate {

    func comboBoxSelectionDidChange(_ notification: Notification) {
     
        if let comboBox = notification.object as? NSComboBox {
            selectedFruit.stringValue = datasource[comboBox.indexOfSelectedItem]
            print (datasource[comboBox.indexOfSelectedItem])
        }
     
    }

}

>> how to actually use that to instigate this change in the TextField


It's not obvious which piece of this you are asking about. You need to:


a. Set up, at an appropriately early time, an observation of the notification. The observation has an associated closure that is invoked to "deliver" the notification to you.


b. The receiver of the notification has to be (or has to know how to find) an object that has a reference to the text field. Typically, the reference would be an "outlet", and would be held by a view controller, or some controller doing a similar job.


c. The controller needs to know how to find the correct string value corresponding to the selected entity. This can be from other state maintained in the controller (and already updated as a result of the selection).


d. The controller can then update the value of the text field.


Which part of that is giving you trouble?


A couple of other comments, which you are free to ignore:


— Core Data is notoriously difficult to use, especially if you're new to Cocoa generally. Yes, it has an overall conceptual coherence, but its actual behavior tends to get more and more inscrutable the deeper you get into the weeds. If it suits you, that's great. If not, it's probably not your fault.


— You seem to be abusing NSComboBox somewhat. A NSComboBox is a kind of text field, not a kind of menu. That means, in particular, it's not really intended to constrain a user to a fixed list of things. (In your description, you add new items via a separate UI, not the combo box itself.) Things will start to get difficult if a user simply types a random string into the combo box, instead of choose a preset string. The correct control is probably a popup menu, NSPopUpButton.


If you use a popup menu, then you likely don't need to use notifications to find out what was chosen. Instead, you can give each menu item its own action (or, since it's dynamic, the same action, and distinguishing between items via their "tag" property).

I had trouble intially getting the NSPopUpButton to update new values dynamically; on the other hand, I believe I figured that out while working with the combobox.


However, the benefit of the combobox is that instead of having to scan through the list of available options (although they can do that with the drop down) a user can start typing in one of the stored values and autocomplete. The use-case is for fetching information about a character and being able to quickly reference that information in the textfield below the combobox. It seemed, once I got to know the combobox a bit better, like a better option than a popupmenu for that reason. It seems to me that if they enter a value that isn't available, it can simply return nil?


However, this business with the tag property does sound much simpler to implement, so I'll play around with it and see which one works best for what I need.


As for which part of the delegate protocol I'm not getting, the first answer does seem to have illuminated the subject a bit. I need to experiment with it and see if I can get it working. But, in essence--and I know that I may just not be looking in the right places--I found information on what the delegate protocols are, and what they do, but not how to actually employ them. So in other words, now that I know I can create a delegate object and access those notifications, how do I make another object an observer to watch for that notification and then do something specific in response like reference the new value selected by the combobox and use that value to populate a corresponding value. These are all just string objects, so there's no terribly complicated code inolved in populating the values in one place or another individually; just in connecting the two actions.


The popupbutton does seem way easier to handle, so thank you for pointing me to that. I hadn't explored the popupbutton thoroughly enough, it seems.

Oops, I misread your original post. I thought you were trying to use a "didChange" notification directly, rather than using a delegate method. Both are possible, and logically (if not actually) the delegate method is invoked as a result of something in the frameworks handling the notification as I described.


But iTen's answer is correct. A view controller is the most usual delegate for this sort of thing (because it's aware of the control's existence), and you simply declare conformance and implement some or all of the protocol methods.


Regarding your use of a combo box as a menu, if autocomplete is important enough then that might be a reasonable solution. You just have to remember that you can't directly prevent the user from typing any random string. That means you need to validate the value before using it, and allow for the fact that what it looks like the control contains isn't necessarily what it effectively contains.

How do I actually employ comboBoxSelectionDidChange to trigger a change elsewhere in the application?
 
 
Q