swiftmacosslidernstouchbarmacbookpro-touch-bar

Swift: How to link Touch Bar controls to main window controls


I'm new to Swift/macOS dev, plenty of dev experience otherwise though. Just trying to make something rudimentary.

Here's my app storyboard:

enter image description here

I'm trying to get:

Q) How do I achieve this?

Note: The main window slider control is wired up and working when I manipulate it e.g.

@IBOutlet weak var mySlider: NSSlider!

@IBAction func mySlider_Changed(_ sender: NSSlider) {
    //... stuff happens here.
}

Solution

  • You'll want your view controller to have some explicit model/state of what the value of these sliders have. e.g.

    class ViewController : NSViewController {
        var value: Double
    }
    

    Then you can connect the sliders and textfield to update or display this value.

    Approach 1: Target/Action/SetValue

    This follows the use of explicit IBActions that you had started. In response to that action, we'll pull the doubleValue from the slider and update the ViewController's model from that:

    @IBAction func sliderValueChanged(_ sender: NSSlider) {
        value = sender.doubleValue
    }
    

    The second piece is updating everything to reflect that new value. With Swift, we can just use the didSet observer on the ViewController's value property to know when it changes and update all of the controls, e.g:

    @IBOutlet weak var touchBarSlider: NSSlider!
    @IBOutlet weak var windowSlider: NSSlider!
    @IBOutlet weak var windowTextField: NSTextField!
    var value: Double {
        didSet {
            touchBarSlider.doubleValue = value
            windowSlider.doubleValue = value
            windowTextField.doubleValue = value
        }
    }
    

    And that's it. You can add a number formatter to the textfield so it nicely displays the value, which you can do in Interface Builder or programmatically. And any other time you change the value, all of the controls will still get updated since they are updated in the didSet observer instead of just the slider action methods.

    Approach 2: Bindings

    Bindings can eliminate a lot of this boiler plate code when it comes to connecting model data to your views.

    With bindings you can get rid of the outlets and the action methods, and have the only thing left in the view controller be:

    class ViewController: NSViewController {
        @objc dynamic var value: Double
    }
    

    The @objc dynamic makes the property be KVO compliant, which is required when using bindings.

    The other piece is establishing bindings from the controls to our ViewController's value property. For all of the controls this is done by through the bindings inspector pane, binding the 'Value' of the control to the View Controller's value key path:

    Bindings Inspector

    And that's it. Again, you could add a number formatter to the textfield, and any other changes to the value property will still update your controls since it will trigger the bindings to it. (you can also still use the didSet observer for value to make other changes that you can't do with bindings)