I'm expanding the functionality of [this SO answer][1].

[1]: http://stackoverflow.com/a/26454949/3804019

Mainly I'm focusing on:

 - You can add as many handlers as you want.
 - You can remove (i.e. cancel) the handler.
 - You can receive the `sender` parameter in the handler closure.
 - You can add "oneshot" handler.

<!--- --->

    import UIKit
    
    extension UIControl {
        private class EventHandler {
            
            let _cb: (UIControl, UIEvent) -> Void
            let _oneshot: Bool
            
            init(_ cb: (UIControl, UIEvent) -> Void, oneshot: Bool) {
                _cb = cb
                _oneshot = oneshot
            }
            
            @objc func invoke(sender: UIControl, event: UIEvent) {
                _cb(sender, event)
                if _oneshot {
                    sender.off(unsafeAddressOf(self))
                }
            }
        }
        
        typealias EventHandlerId = UnsafePointer<Void>
    
        func on<T: UIControl>(events: UIControlEvents, _ callback: (T, UIEvent) -> Void) -> EventHandlerId {
            assert(self.isKindOfClass(T), "The handler must receive \(NSStringFromClass(self.dynamicType)) or UIControl")
            return self._on(events, EventHandler({ callback($0 as T, $1) }, oneshot: false))
        }
        func once<T: UIControl>(events: UIControlEvents, _ callback: (T, UIEvent) -> Void) -> EventHandlerId {
            assert(self.isKindOfClass(T), "The handler must receive \(NSStringFromClass(self.dynamicType)) or UIControl")
            return self._on(events, EventHandler({ callback($0 as T, $1) }, oneshot: true))
        }
    
        func on(events: UIControlEvents, _ callback: () -> Void) -> EventHandlerId {
            return self._on(events, EventHandler({ _, _ in callback() }, oneshot: false))
        }
        func once(events: UIControlEvents, _ callback: () -> Void) -> EventHandlerId {
            return self._on(events, EventHandler({ _, _ in callback() }, oneshot: true))
        }
    
        private func _on(events: UIControlEvents, _ handler: EventHandler) -> EventHandlerId {
            let ptr = unsafeAddressOf(handler)
            self.addTarget(handler, action: "invoke:event:", forControlEvents: events)
            objc_setAssociatedObject(self, ptr, handler, objc_AssociationPolicy(OBJC_ASSOCIATION_RETAIN_NONATOMIC))
            return ptr
        }
        
        func off(identifier: EventHandlerId) {
            if let handler = objc_getAssociatedObject(self, identifier) as? EventHandler {
                self.removeTarget(handler, action: nil, forControlEvents: .AllEvents)
                objc_setAssociatedObject(self, identifier, nil, 0)
            }
        }
    }
    
    
Usage:
    
    class MyViewController:UIViewController {
        
        @IBOutlet weak var myButton:UIButton!
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            // add event handler
            let handle = myButton.on(.TouchUpInside) { (sender, event) in
                // `sender` is the control itself.
                // `event` is the UIEvent object.
            }
    
            // remove event handler
            myButton.off(handle)
    
            // event handler can be () -> Void type
            myButton.on(.TouchUpInside) { [unowned self] in
                // your work
            }
            
            // "oneshot" event handler
            myButton.once(.TouchUpInside) {
                // your work
            }
        }
    }

It's working OK... But, for example:

    let btn = UIButton()
    btn.on(.TouchUpInside) { (sender: UISwitch, _) in /* ... */ }
                                      ^^^^^^^^

This compiles, but I want to make this compile time error.


Currently, as a workaround, I'm doing "assertion":

    assert(self.isKindOfClass(T), "The handler must receive \(NSStringFromClass(self.dynamicType)) or UIControl")

And, if possible, I wish the compiler could infer the type of the `sender`, like this:

    let btn = UIButton()
    btn.on(.TouchUpInside) { sender, _ in
        sender.titleLabel.text = "Pushed !!"
    }

Any ideas?