|
typealias ButtonAction = (button: UIButton) -> Void |
|
|
|
class ButtonActionWrapper: NSObject { |
|
var action: ButtonAction |
|
|
|
init(action: ButtonAction) { |
|
self.action = action |
|
} |
|
} |
|
|
|
private struct ButtonActionKeys { |
|
static var tap = "this is the tap key" |
|
static var touchDown = "this is the touch down key" |
|
static var touchLift = "this is the touch lift key" |
|
} |
|
|
|
extension UIButton { |
|
var tapAction: ButtonAction? { |
|
get { |
|
if let wrapper = objc_getAssociatedObject(self, &ButtonActionKeys.tap) as? ButtonActionWrapper { |
|
return wrapper.action |
|
} |
|
return nil |
|
} |
|
set { |
|
if let anAction = newValue { |
|
addTarget(self, action: #selector(runTapAction), forControlEvents: .TouchUpInside) |
|
objc_setAssociatedObject(self, &ButtonActionKeys.tap, ButtonActionWrapper(action: anAction), objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) |
|
} else { |
|
removeTarget(self, action: #selector(runTapAction), forControlEvents: .TouchUpInside) |
|
} |
|
} |
|
} |
|
|
|
var touchDownAction: ButtonAction? { |
|
get { |
|
if let wrapper = objc_getAssociatedObject(self, &ButtonActionKeys.touchDown) as? ButtonActionWrapper { |
|
return wrapper.action |
|
} |
|
return nil |
|
} |
|
set { |
|
if let anAction = newValue { |
|
addTarget(self, action: #selector(runTouchDownAction), forControlEvents: .TouchDown) |
|
objc_setAssociatedObject(self, &ButtonActionKeys.touchDown, ButtonActionWrapper(action: anAction), objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) |
|
} else { |
|
removeTarget(self, action: #selector(runTouchDownAction), forControlEvents: .TouchDown) |
|
} |
|
} |
|
} |
|
|
|
var touchLiftAction: ButtonAction? { |
|
get { |
|
if let wrapper = objc_getAssociatedObject(self, &ButtonActionKeys.touchLift) as? ButtonActionWrapper { |
|
return wrapper.action |
|
} |
|
return nil |
|
} |
|
set { |
|
if let anAction = newValue { |
|
addTarget(self, action: #selector(runTouchLiftAction), forControlEvents: .TouchCancel) |
|
objc_setAssociatedObject(self, &ButtonActionKeys.touchLift, ButtonActionWrapper(action: anAction), objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) |
|
} else { |
|
removeTarget(self, action: #selector(runTouchLiftAction), forControlEvents: .TouchCancel) |
|
} |
|
} |
|
} |
|
|
|
func runTapAction() { |
|
touchLiftAction?(button: self) |
|
tapAction?(button: self) |
|
} |
|
|
|
func runTouchDownAction() { |
|
touchDownAction?(button: self) |
|
} |
|
|
|
func runTouchLiftAction() { |
|
touchLiftAction?(button: self) |
|
} |
|
} |
An evolution of the target-action model for the Swift era. Target is always
self
, since other objects can easily be called from inside the closure. This allows for faster prototyping, potentially cleaner class interfaces with less "buttonTapped
" methods, and a pattern closer to Swift property observers.tapAction
is equivalent to an action called on.TouchUpInside
touchDownAction
is equivalent to an action called on.TouchDown
touchLiftAction
is equivalent to an action called on either.TouchUpInside
or.TouchCancel
Example call site usage: