How do I replace target/action with callbacks in Swift?
NSButton uses the target/action pattern: a button : NSButton has two properties button.target and button.action which specify what to call when the button is clicked.
This is rather different to the way I’m used to programming: I’d like to just set button.onClick = { ... do some stuff ... }. In short, this is how to do it:
class CallbackWrapper {
var callback : () -> ();
init(callback: @escaping () -> ()) {
self.callback = callback;
}
@objc public func callCallback() {
self.callback();
}
}
func setTargetActionCallback(control: NSControl, callback: @escaping () -> ()) {
let wrapper = CallbackWrapper(callback: callback);
control.target = wrapper;
control.action = #selector(CallbackWrapper.callCallback);
let key = UnsafeMutablePointer<Int8>.allocate(capacity: 1);
objc_setAssociatedObject(control, key, wrapper, .OBJC_ASSOCIATION_RETAIN);
}
Explanation:
- We wrap the callback in an object, so
wrapper.callCallback()is the same ascallback() - We use
wrapperas the target and itscallCallbackmethod as the action - We set the wrapper as an associated object of the button. This is important because
button.targetis a weak reference, for questionable design reasons!
Thanks to Mike Ash and Ham Chapman for finding that post.
This page copyright James Fisher 2016. Content is not associated with my employer.
Granola