Skip to content

Instantly share code, notes, and snippets.

@PEZ
Created September 20, 2017 23:04
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save PEZ/e4a790870855a0bb3a45da2da8f71aa3 to your computer and use it in GitHub Desktop.
Save PEZ/e4a790870855a0bb3a45da2da8f71aa3 to your computer and use it in GitHub Desktop.
Swift3 UIControl extension for adding block event listeners. Adapted from: https://stackoverflow.com/a/44917661/44639
import Foundation
import UIKit
extension UIControl {
func listen(_ action: @escaping () -> (), for controlEvents: UIControlEvents) -> AnyObject {
let sleeve = ClosureSleeve(attachTo: self, closure: action, controlEvents: controlEvents)
addTarget(sleeve, action: #selector(ClosureSleeve.invoke), for: controlEvents)
return sleeve
}
func listenOnce(_ action: @escaping () -> (), for controlEvents: UIControlEvents) {
let sleeve = ClosureSleeve(attachTo: self, closure: action, controlEvents: controlEvents)
addTarget(sleeve, action: #selector(ClosureSleeve.invokeOnce), for: controlEvents)
}
func unlisten(sleeve: AnyObject) {
guard let sleeve = sleeve as? ClosureSleeve else { return }
self.removeTarget(sleeve, action: #selector(ClosureSleeve.invoke), for: sleeve.controlEvents)
}
}
private class ClosureSleeve {
let closure: () -> ()
let controlEvents:UIControlEvents
let attachedTo: AnyObject
init(attachTo: AnyObject, closure: @escaping () -> (), controlEvents:UIControlEvents) {
self.attachedTo = attachTo
self.closure = closure
self.controlEvents = controlEvents
objc_setAssociatedObject(attachTo, "[\(arc4random())]", self, .OBJC_ASSOCIATION_RETAIN)
}
@objc func invoke() {
closure()
}
@objc func invokeOnce() {
closure()
attachedTo.unlisten(sleeve: self)
}
}
// Register listener, keep the reference to unregister the listener
let listener = button.listenOnce({
print("I will say this every time you tap the button")
}, for: [.touchUpInside])
// … later …
button.unlisten(listener)
// Listen once for the control events, automatically unlisten when the block is performed
button.listenOnce({
print("I will only say this once")
}, for: [.touchUpInside, .touchDragExit])
@PEZ
Copy link
Author

PEZ commented Sep 21, 2017

Wow, super duper feedback! Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment