Skip to content

Instantly share code, notes, and snippets.

@sindresorhus
Last active June 13, 2020 06:50
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sindresorhus/3580ce9426fff8fafb1677341fca4815 to your computer and use it in GitHub Desktop.
Save sindresorhus/3580ce9426fff8fafb1677341fca4815 to your computer and use it in GitHub Desktop.
NSControl extension for closure version of `.action`
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
}
}
}
@0xWDG
Copy link

0xWDG commented Jun 12, 2020

error: use of unresolved identifier 'AssociatedObject'
        static let onActionClosure = AssociatedObject<ActionClosure>()

@sindresorhus
Copy link
Author

Fixed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment