New in iOS 14, we can attach an action handler directly to a UIControl:
let action = UIAction(title:"") { action in
print("howdy!")
}
button.addAction(action, for: .touchUpInside)
That's cool in its way, but the syntax is infuriating. I have to form the UIAction first. I have to give the UIAction a title, even though that title will never appear in the interface. Isn't there a better way?
First, you don't need to supply the title. This is (now) legal:
let action = UIAction { action in
print("howdy!")
}
button.addAction(action, for: .touchUpInside)
Second, you don't really need the separate line to define the action, so you can say this:
button.addAction(.init { action in
print("howdy!")
}, for: .touchUpInside)
However, that's still infuriating, because now I've got a closure in the middle of the addAction
call. It ought to be a trailing closure! The obvious solution is an extension:
extension UIControl {
func addAction(for event: UIControl.Event, handler: @escaping UIActionHandler) {
self.addAction(UIAction(handler:handler), for:event)
}
}
Problem solved! Now I can talk the way I should have been permitted to all along:
button.addAction(for: .touchUpInside) { action in
print("howdy!")
}
[Extra info: Where's the sender
in this story? It's inside the action. UIAction has a sender
property. So in that code, action.sender
is the UIButton.]