Is there a way to set related objects in Swift?

Based on goal C, you can call the objc_setAssociatedObject function between two objects to maintain the link, which can be convenient if at run time you do not want the object to be destroyed until its link is deleted. Is there something similar to this?

+68
swift
Jun 10 '14 at 4:48
source share
7 answers

Here is a simple but complete example derived from jckarter's answer .

Shows how to add a new property to an existing class. He does this by defining a computed property in an extension block. The computed property is saved as a related 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 avoid getting an error unexpectedly found nil while unwrapping an Optional value , you can change the receiver as follows:

  get { return objc_getAssociatedObject(self, &AssociatedObjectHandle) as? String ?? "" } 
+110
Aug 21 '14 at 2:03
source share

The solution supports all types of values , and not just those that are automatic, such as String, Int, Double, etc.

Packers

 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 } } 

Possible class extension (usage example)

 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) } } } } 
+26
Apr 15 '15 at 23:13
source share

Obviously, this only works with Objective-C objects. After playing around a bit with this, here's how to call Swift:

 import ObjectiveC // Define a variable whose address we'll use as key. // "let" doesn't work here. var kSomeKey = "s" … func someFunc() { objc_setAssociatedObject(target, &kSomeKey, value, UInt(OBJC_ASSOCIATION_RETAIN)) let value : AnyObject! = objc_getAssociatedObject(target, &kSomeKey) } 
+4
Jul 05 '14 at 10:32
source share

Update in Swift 3.0 For example, this is a UITextField

 import Foundation import UIKit import ObjectiveC // Declare a global var to produce a unique address as the assoc object handle var AssociatedObjectHandle: UInt8 = 0 extension UITextField { var nextTextField:UITextField { get { return objc_getAssociatedObject(self, &AssociatedObjectHandle) as! UITextField } set { objc_setAssociatedObject(self, &AssociatedObjectHandle, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } } } 
+3
Nov 29 '16 at 9:28
source share

Klaas will respond only to Swift 2.1:

 import ObjectiveC let value = NSUUID().UUIDString var associationKey: UInt8 = 0 objc_setAssociatedObject(parentObject, &associationKey, value, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC) let fetchedValue = objc_getAssociatedObject(parentObject, &associationKey) as! String 
+2
Feb 04 '16 at 8:43
source share

Just add #import <objc/runtime.h> to your header file to access the objc_setAssociatedObject object under quick code

0
Jun 10 '14 at 5:38
source share

The above friend answered your question, but if it is related to closure properties, please note:

`` ``

 import UIKit public extension UICollectionView { typealias XYRearrangeNewDataBlock = (_ newData: [Any]) -> Void typealias XYRearrangeOriginaDataBlock = () -> [Any] // MARK:- associat key private struct xy_associatedKeys { static var originalDataBlockKey = "xy_originalDataBlockKey" static var newDataBlockKey = "xy_newDataBlockKey" } private class BlockContainer { var rearrangeNewDataBlock: XYRearrangeNewDataBlock? var rearrangeOriginaDataBlock: XYRearrangeOriginaDataBlock? } private var newDataBlock: BlockContainer? { get { if let newDataBlock = objc_getAssociatedObject(self, &xy_associatedKeys.newDataBlockKey) as? BlockContainer { return newDataBlock } return nil } set(newValue) { objc_setAssociatedObject(self, xy_associatedKeys.newDataBlockKey, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC) } } convenience init(collectionVewFlowLayout : UICollectionViewFlowLayout, originalDataBlock: @escaping XYRearrangeOriginaDataBlock, newDataBlock: @escaping XYRearrangeNewDataBlock) { self.init() let blockContainer: BlockContainer = BlockContainer() blockContainer.rearrangeNewDataBlock = newDataBlock blockContainer.rearrangeOriginaDataBlock = originalDataBlock self.newDataBlock = blockContainer } 

`` ``

0
Nov 10 '16 at 8:22
source share



All Articles