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.setTitle("Pushed !!", forState: .Normal)
    }

Any ideas?

----

**Added**: to reply the @nhgrif answer:

Why I did **not** implement the `sender` only version like this:

    func on<T: UIControl>(events:UIControlEvents, _ callback: T -> Void) -> EventHandlerId {
        assert(self.isKindOfClass(T), "The handler must receive \(NSStringFromClass(self.dynamicType)) or UIControl")
        return self._on(events, EventHandler({ sender, _ in callback(sender as T) }, oneshot: true))
    }

That is because of a purely technical problem: It conflict with `() -> Void` version.

    btn.on(.TouchUpInside) { return }                       // OK: () -> Void
    btn.on(.TouchUpInside) { (sender: UIButton) in return } // OK: T -> Void
    btn.on(.TouchUpInside) { sender in return }             // NG: () -> Void

In the last case, the compiler infers the type of `sender` as `()` :(

And why I declared `EventHandler` as `private`, that is I don't want users do like this:

    let handler = UIControl.EventHandler({ ... }, oneshot: true)

    btn.on(.TouchUpInside, handler)
    btn.on(.TouchDown, handler)
    btn.off(handler)

With my current code, `.off()` removes the handler from `.AllEvents`, and from associated objects. There is no way to remove it from specific event. Maybe, if we do want to do that, we can remember the registered events and handle them, but It's too much I think. Moreover, for such use case, we can simply use `addTarget()` and `removeTarget()` with custom handler object.