I'm new to Swift/macOS dev, plenty of dev experience otherwise though. Just trying to make something rudimentary.
Here's my app storyboard:
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.
}
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:
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)