Skip to content

Instantly share code, notes, and snippets.

@desyatov
Created April 23, 2021 18:10
Show Gist options
  • Save desyatov/6ed83de58ca1146d85fedab461a69b12 to your computer and use it in GitHub Desktop.
Save desyatov/6ed83de58ca1146d85fedab461a69b12 to your computer and use it in GitHub Desktop.
import Foundation
import UIKit
/**
* An extension for UIControl that lets you set action handlers using closures.
*/
extension UIControl {
/**
* A map of closures, mapped as [ event : action ] .
*/
typealias Handlers = [UInt:((UIControl) -> Void)]
private enum AssociatedKey {
static var actionHandlers = "UIControl.actionHandlers"
}
private var actionHandlers: Handlers {
get {
return objc_getAssociatedObject(self, &AssociatedKey.actionHandlers) as? Handlers ?? [:]
}
set(newValue) {
objc_setAssociatedObject(self, &AssociatedKey.actionHandlers, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
}
}
/**
* Retrieve the handler associated with the specified event for this instance
* if any exists, otherwise return nil.
*/
private func getHandler(_ event: UIControl.Event) -> ((UIControl) -> Void)? {
return actionHandlers[event.rawValue]
}
/**
* Set the action for the specified event.
*
* - parameter event: The event for which to set the action.
* - parameter action: The action to perform when the event is raised.
*/
public func action(_ event: UIControl.Event, _ action: @escaping (UIControl) -> Void) {
actionHandlers[event.rawValue] = action
switch event {
case .touchDown:
self.addTarget(self, action: #selector(triggerTouchDown), for: event)
case .touchDownRepeat:
self.addTarget(self, action: #selector(triggerTouchDownRepeat), for: event)
case .touchDragInside:
self.addTarget(self, action: #selector(triggerTouchDragInside), for: event)
case .touchDragOutside:
self.addTarget(self, action: #selector(triggerTouchDragOutside), for: event)
case .touchDragEnter:
self.addTarget(self, action: #selector(triggerTouchDragEnter), for: event)
case .touchDragExit:
self.addTarget(self, action: #selector(triggerTouchDragExit), for: event)
case .touchUpInside:
self.addTarget(self, action: #selector(triggerTouchUpInside), for: event)
case .touchUpOutside:
self.addTarget(self, action: #selector(triggerTouchUpOutside), for: event)
case .touchCancel:
self.addTarget(self, action: #selector(triggerTouchCancel), for: event)
case .valueChanged:
self.addTarget(self, action: #selector(triggerValueChanged), for: event)
case .primaryActionTriggered:
self.addTarget(self, action: #selector(triggerPrimaryActionTriggered), for: event)
case .editingDidBegin:
self.addTarget(self, action: #selector(triggerEditingDidBegin), for: event)
case .editingDidEnd:
self.addTarget(self, action: #selector(triggerEditingDidEnd), for: event)
case .editingChanged:
self.addTarget(self, action: #selector(triggerEditingChanged), for: event)
case .editingDidEndOnExit:
self.addTarget(self, action: #selector(triggerEditingDidEndOnExit), for: event)
case .allTouchEvents:
self.addTarget(self, action: #selector(triggerAllTouchEvents), for: event)
case .allEditingEvents:
self.addTarget(self, action: #selector(triggerAllEditingEvents), for: event)
case .applicationReserved:
self.addTarget(self, action: #selector(triggerApplicationReserved), for: event)
case .systemReserved:
self.addTarget(self, action: #selector(triggerSystemReserved), for: event)
case .allEvents:
self.addTarget(self, action: #selector(triggerAllEvents), for: event)
default: break
}
}
// selector definitions below this line
@objc private func triggerTouchDown() {
getHandler(.touchDown)?(self)
}
@objc private func triggerTouchDownRepeat() {
getHandler(.touchDownRepeat)?(self)
}
@objc private func triggerTouchDragInside() {
getHandler(.touchDragInside)?(self)
}
@objc private func triggerTouchDragOutside() {
getHandler(.touchDragOutside)?(self)
}
@objc private func triggerTouchDragEnter() {
getHandler(.touchDragEnter)?(self)
}
@objc private func triggerTouchDragExit() {
getHandler(.touchDragExit)?(self)
}
@objc private func triggerTouchUpInside() {
getHandler(.touchUpInside)?(self)
}
@objc private func triggerTouchUpOutside() {
getHandler(.touchUpOutside)?(self)
}
@objc private func triggerTouchCancel() {
getHandler(.touchCancel)?(self)
}
@objc private func triggerValueChanged() {
getHandler(.valueChanged)?(self)
}
@objc private func triggerPrimaryActionTriggered() {
getHandler(.primaryActionTriggered)?(self)
}
@objc private func triggerEditingDidBegin() {
getHandler(.editingDidBegin)?(self)
}
@objc private func triggerEditingChanged() {
getHandler(.editingChanged)?(self)
}
@objc private func triggerEditingDidEnd() {
getHandler(.editingDidEnd)?(self)
}
@objc private func triggerEditingDidEndOnExit() {
getHandler(.editingDidEndOnExit)?(self)
}
@objc private func triggerAllTouchEvents() {
getHandler(.allTouchEvents)?(self)
}
@objc private func triggerAllEditingEvents() {
getHandler(.allEditingEvents)?(self)
}
@objc private func triggerApplicationReserved() {
getHandler(.applicationReserved)?(self)
}
@objc private func triggerSystemReserved() {
getHandler(.systemReserved)?(self)
}
@objc private func triggerAllEvents() {
getHandler(.allEvents)?(self)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment