Coming from Objective-C you can call function objc_setAssociatedObject
between 2 objects to have them maintain a reference, which can be handy if at runtime you don't want an object to be destroyed until its reference is removed also. Does Swift have anything similar to this?
Associated Objects is part of Objective-C runtime. It allow you to associate objects at runtime. Simply, you can attach any object to any other object without subclassing.
Associated Objects—or Associative References, as they were originally known—are a feature of the Objective-C 2.0 runtime, introduced in OS X Snow Leopard (available in iOS 4). The term refers to the following three C functions declared in <objc/runtime.
Sets an associated value for a given object using a given key and association policy.
Here is a simple but complete example derived from jckarter's answer.
It shows how to add a new property to an existing class. It does it by defining a computed property in an extension block. The computed property is stored as an associated object:
import ObjectiveC // Declare a global var to produce a unique address as the assoc object handle private var AssociatedObjectHandle: UInt8 = 0 extension MyClass { var stringProperty:String { get { return objc_getAssociatedObject(self, &AssociatedObjectHandle) as! String } set { objc_setAssociatedObject(self, &AssociatedObjectHandle, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) } } }
EDIT:
If you need to support getting the value of an uninitialized property and to avoid getting the error unexpectedly found nil while unwrapping an Optional value
, you can modify the getter like this:
get { return objc_getAssociatedObject(self, &AssociatedObjectHandle) as? String ?? "" }
The solution supports all the value types as well, and not only those that are automagically bridged, such as String, Int, Double, etc.
Wrappers
import ObjectiveC final class Lifted<T> { let value: T init(_ x: T) { value = x } } private func lift<T>(x: T) -> Lifted<T> { return Lifted(x) } func setAssociatedObject<T>(object: AnyObject, value: T, associativeKey: UnsafePointer<Void>, policy: objc_AssociationPolicy) { if let v: AnyObject = value as? AnyObject { objc_setAssociatedObject(object, associativeKey, v, policy) } else { objc_setAssociatedObject(object, associativeKey, lift(value), policy) } } func getAssociatedObject<T>(object: AnyObject, associativeKey: UnsafePointer<Void>) -> T? { if let v = objc_getAssociatedObject(object, associativeKey) as? T { return v } else if let v = objc_getAssociatedObject(object, associativeKey) as? Lifted<T> { return v.value } else { return nil } }
A possible Class extension (Example of usage)
extension UIView { private struct AssociatedKey { static var viewExtension = "viewExtension" } var referenceTransform: CGAffineTransform? { get { return getAssociatedObject(self, associativeKey: &AssociatedKey.viewExtension) } set { if let value = newValue { setAssociatedObject(self, value: value, associativeKey: &AssociatedKey.viewExtension, policy: objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) } } } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With