Swift package
Stored-like properties for Objective-C objects, with helpers and macros
Objective-C associated objects are powerful, but correct getters, stable keys, initialization, and policies add boilerplate. The @AssociatedObject macro turns that machinery into a property declaration while keeping ownership choices visible.
import ObjectiveC
import UIKit
private enum RetryCountKey {
static var value: UInt8 = 0
}
extension UIViewController {
var retryCount: Int {
get {
objc_getAssociatedObject(
self,
&RetryCountKey.value
) as? Int ?? 0
}
set {
objc_setAssociatedObject(
self,
&RetryCountKey.value,
newValue,
.OBJC_ASSOCIATION_RETAIN_NONATOMIC
)
}
}
}
import AssociatedObjectsMacros
import UIKit
extension UIViewController {
@AssociatedObject(readonly: false)
var retryCount: Int = 0
}
Use readonly: true for lazily initialized state that should not be replaced, .atomic when atomic Objective-C association access is required, and .assign only for an intentionally non-owning, non-zeroing reference.
@AssociatedObject(readonly: true)
var state: State = .init()
@AssociatedObject(
policy: .assign,
readonly: false
)
var delegateReference: AnyObject?
The macro product adds SwiftSyntax to cold builds. Link only AssociatedObjects when the helper functions and AssociatingObject instance API are the better trade-off.
Every NSObject subclass conforms to AssociatingObject, so UIKit and AppKit extensions can use typed instance helpers without importing the macro product. A complex getter can lazily construct and configure an object while a simple setter remains easy to find first:
import AssociatedObjects
import UIKit
extension UIViewController {
var refreshControl: UIRefreshControl {
set {
setAssociatedObject(
newValue,
forKey: #function
)
}
get {
getAssociatedObject(forKey: #function) ?? {
let refreshControl = UIRefreshControl()
refreshControl.tintColor = .secondaryLabel
refreshControl.attributedTitle = NSAttributedString(
string: "Pull to refresh"
)
setAssociatedObject(
refreshControl,
forKey: #function
)
return refreshControl
}()
}
}
}
#function is a concise stable key when the association belongs to one property. Prefer an explicitly namespaced StaticString when keys could collide across accessors or modules. For Objective-C objects that do not conform to AssociatingObject, the package also provides _getAssociatedObject(...from:) and _setAssociatedObject(...to:).
| Option | Meaning |
|---|---|
readonly: true | Lazily initialize once and prevent replacement |
threadSafety: .atomic | Use atomic Objective-C association access |
policy: .assign | Store an intentionally non-owning, non-zeroing reference |
getAssociatedObject / setAssociatedObject | Avoid the macro product while keeping typed helpers |
Associated objects require Objective-C runtime identity. Prefer an ordinary stored property whenever the original class is under your control.