Skip to content

Instantly share code, notes, and snippets.

@IanKeen
Created April 3, 2016 21:04
Show Gist options
  • Save IanKeen/f9103433314230f5ac86795320c3344f to your computer and use it in GitHub Desktop.
Save IanKeen/f9103433314230f5ac86795320c3344f to your computer and use it in GitHub Desktop.
UIControl.swift - Adds a closure based target/action support to all UIControl based components, including basic lifecycle handling
public protocol ClosureActionable: class {
func addTarget(target: AnyObject, forControlEvents controlEvents: UIControlEvents, closure: (Self) -> Void) -> AnyObject
func removeTarget(pointer: AnyObject)
}
extension UIControl: ClosureActionable { }
public extension ClosureActionable where Self: UIControl {
private var pointers: [TargetPointer] {
get {
if let existing = objc_getAssociatedObject(self, ClosureAssociatedKeys.Pointers) as? [TargetPointer] { return existing }
self.pointers = []
return self.pointers
}
set {
objc_setAssociatedObject(self, ClosureAssociatedKeys.Pointers, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
public func addTarget(target: AnyObject, forControlEvents controlEvents: UIControlEvents, closure: (Self) -> Void) -> AnyObject {
let pointer = TargetPointer(self, target: target, controlEvents: controlEvents) {
if let _ = $0.target { closure(self) }
else { self.removeTarget($0) }
}
self.pointers.append(pointer)
self.addTarget(pointer, action: "actionTriggered", forControlEvents: controlEvents)
return pointer
}
public func removeTarget(pointer: AnyObject) {
guard let pointer = pointer as? TargetPointer else { return }
self.removeTarget(pointer, action: "actionTriggered", forControlEvents: pointer.controlEvents)
}
}
private struct ClosureAssociatedKeys {
static var Pointers = "Pointers"
}
private class TargetPointer: NSObject {
weak var target: AnyObject?
let controlEvents: UIControlEvents
private let closure: (TargetPointer) -> Void
init(_ control: UIControl, target: AnyObject, controlEvents: UIControlEvents, closure: (TargetPointer) -> Void) {
self.target = target
self.controlEvents = controlEvents
self.closure = closure
}
@objc private func actionTriggered() { self.closure(self) }
}
let pointer = button.addTarget(target, forControlEvents: .TouchUpInside) { btn in
//..
}
/* either of the following two things would stop the closure from being fired */
target = nil
button.removeTarget(pointer)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment