Last active
June 13, 2020 06:50
-
-
Save sindresorhus/3580ce9426fff8fafb1677341fca4815 to your computer and use it in GitHub Desktop.
NSControl extension for closure version of `.action`
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
enum AssociationPolicy { | |
case assign | |
case retainNonatomic | |
case copyNonatomic | |
case retain | |
case copy | |
var rawValue: objc_AssociationPolicy { | |
switch self { | |
case .assign: | |
return .OBJC_ASSOCIATION_ASSIGN | |
case .retainNonatomic: | |
return .OBJC_ASSOCIATION_RETAIN_NONATOMIC | |
case .copyNonatomic: | |
return .OBJC_ASSOCIATION_COPY_NONATOMIC | |
case .retain: | |
return .OBJC_ASSOCIATION_RETAIN | |
case .copy: | |
return .OBJC_ASSOCIATION_COPY | |
} | |
} | |
} | |
final class ObjectAssociation<T: Any> { | |
private let policy: AssociationPolicy | |
init(policy: AssociationPolicy = .retainNonatomic) { | |
self.policy = policy | |
} | |
subscript(index: AnyObject) -> T? { | |
get { | |
// Force-cast is fine here as we want it to fail loudly if we don't use the correct type. | |
// swiftlint:disable:next force_cast | |
objc_getAssociatedObject(index, Unmanaged.passUnretained(self).toOpaque()) as! T? | |
} | |
set { | |
objc_setAssociatedObject(index, Unmanaged.passUnretained(self).toOpaque(), newValue, policy.rawValue) | |
} | |
} | |
} | |
extension NSControl { | |
typealias ActionClosure = ((NSControl) -> Void) | |
private struct AssociatedKeys { | |
static let onActionClosure = ObjectAssociation<ActionClosure>() | |
} | |
@objc | |
private func callClosure(_ sender: NSControl) { | |
onAction?(sender) | |
} | |
/** | |
Closure version of `.action`. | |
``` | |
let button = NSButton(title: "Unicorn", target: nil, action: nil) | |
button.onAction = { sender in | |
print("Button action: \(sender)") | |
} | |
``` | |
*/ | |
var onAction: ActionClosure? { | |
get { | |
return AssociatedKeys.onActionClosure[self] | |
} | |
set { | |
AssociatedKeys.onActionClosure[self] = newValue | |
action = #selector(callClosure) | |
target = self | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment