Skip to content

Instantly share code, notes, and snippets.

@unknown-undefined
Last active September 16, 2021 02:23
Show Gist options
  • Save unknown-undefined/265cb5ad5dce3dcb376b24271b07eb42 to your computer and use it in GitHub Desktop.
Save unknown-undefined/265cb5ad5dce3dcb376b24271b07eb42 to your computer and use it in GitHub Desktop.
UIControl block call back
import UIKit
extension UIControl {
/// add handler for specific `UIControl.Event`
func addEvent(_ event: UIControl.Event, handler: @escaping (UIControl) -> Void) {
let holder = EventHandlerHolder(action: handler)
retainHolder(holder, for: event)
addTarget(holder, action: #selector(holder.invokeHandler), for: event)
}
/// remove all `handler` of specific `UIControl.Event`
func removeHandlers(for event: UIControl.Event) {
var dic = eventHolderDictionary
let oldKeys = dic.keys
.map(\.uintValue)
.map(UIControl.Event.init(rawValue:))
let eventsToModify = oldKeys.filter { $0.contains(event) } + [event]
eventsToModify.forEach { oldEvent in
let oldKey = NSNumber(value: oldEvent.rawValue)
let newEvent = oldEvent.subtracting(event)
if newEvent.isEmpty {
dic[oldKey]?.forEach({ holder in
removeTarget(holder, action: #selector(holder.invokeHandler), for: oldEvent)
})
dic[oldKey] = nil
} else {
dic[oldKey]?.forEach({ holder in
removeTarget(holder, action: #selector(holder.invokeHandler), for: oldEvent)
addTarget(holder, action: #selector(holder.invokeHandler), for: newEvent)
})
let newKey = NSNumber(value: newEvent.rawValue)
dic[newKey] = dic[oldKey]
dic[oldKey] = nil
}
}
eventHolderDictionary = dic
}
}
private var eventHolderDictionaryKey: Void?
extension UIControl {
private func retainHolder(_ holder: EventHandlerHolder, for event: UIControl.Event) {
let key = NSNumber(value: event.rawValue)
var dic = eventHolderDictionary
let holders = dic[key] ?? []
dic[key] = holders.union([holder])
eventHolderDictionary = dic
}
private var eventHolderDictionary: [NSNumber: Set<EventHandlerHolder>] {
get {
let obj = objc_getAssociatedObject(self, &eventHolderDictionaryKey) as? [NSNumber: Set<EventHandlerHolder>]
return obj ?? [:]
}
set {
objc_setAssociatedObject(self, &eventHolderDictionaryKey, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC)
}
}
private final class EventHandlerHolder: NSObject {
let action: (UIControl) -> Void
init(action: @escaping (UIControl) -> Void) {
self.action = action
}
@objc fileprivate func invokeHandler(sender: UIControl) {
action(sender)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment