Skip to content

Instantly share code, notes, and snippets.

@DanielCardonaRojas
Created July 28, 2020 14:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DanielCardonaRojas/4389a0091e869874e440e9ab2639a359 to your computer and use it in GitHub Desktop.
Save DanielCardonaRojas/4389a0091e869874e440e9ab2639a359 to your computer and use it in GitHub Desktop.
Add closure targets to UIControl subclasses.
import UIKit
public typealias Action = (UIControl) -> Void
extension NSObject {
var uniqueId: String {
return String(describing: self)
}
}
private struct AssociatedKey {
static var key = "EZAction_TargetContainer"
}
// MARK: - EZAction
public protocol EZAction: class {
associatedtype EZActionHost: AnyObject
var targetContainer: TargetContainer<EZActionHost> { get }
}
extension EZAction {
public var targetContainer: TargetContainer<Self> {
get {
if let value = objc_getAssociatedObject(self, &AssociatedKey.key) as? TargetContainer<Self> {
return value
}
let value = TargetContainer(host: self)
objc_setAssociatedObject(self, &AssociatedKey.key, value, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
return value
}
}
}
// MARK: TargetContainer
public class TargetContainer<Host: AnyObject>: NSObject {
public unowned let host: Host
public init(host: Host) {
self.host = host
}
// Keep all targets alive
public var targets = [String: NSObject]()
}
public extension TargetContainer where Host: UIControl {
func addAction(_ action: @escaping Action, for event: Host.Event) {
let target = UIControlTarget(host: host, action: action, event: event)
targets[target.uniqueId] = target
}
}
class UIControlTarget: NSObject {
var action: Action?
init(host: UIControl, action: @escaping Action, event: UIControl.Event) {
super.init()
self.action = action
host.addTarget(self, action: #selector(handleEvent), for: event)
}
// MARK: - Action
@objc func handleEvent(_ sender: UIControl) {
action?(sender)
}
}
// MARK: Extensions
extension NSObject: EZAction { }
extension EZAction where Self: UIControl {
public func on(_ event: Self.Event, action: @escaping Action) {
self.targetContainer.addAction(action, for: event)
}
public func on(_ event: Self.Event, action: @escaping () -> Void) {
self.targetContainer.addAction({ _ in action() }, for: event)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment