Von Ziel C aus können Sie die Funktion objc_setAssociatedObject
zwischen zwei Objekten aufrufen , damit diese eine Referenz verwalten. Dies kann hilfreich sein, wenn Sie zur Laufzeit nicht möchten, dass ein Objekt zerstört wird, bis auch seine Referenz entfernt wird. Hat Swift etwas Ähnliches?
82
objc_setAssociatedObject
von Swift verwenden: developer.apple.com/library/prerelease/ios/documentation/Swift/…Antworten:
Hier ist ein einfaches, aber vollständiges Beispiel, das aus der Antwort von jckarter abgeleitet wurde .
Es zeigt, wie Sie einer vorhandenen Klasse eine neue Eigenschaft hinzufügen. Dazu wird eine berechnete Eigenschaft in einem Erweiterungsblock definiert. Die berechnete Eigenschaft wird als zugehöriges Objekt gespeichert:
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) } } }
BEARBEITEN:
Wenn Sie das Abrufen des Werts einer nicht initialisierten Eigenschaft unterstützen und den Fehler vermeiden möchten
unexpectedly found nil while unwrapping an Optional value
, können Sie den Getter folgendermaßen ändern:get { return objc_getAssociatedObject(self, &AssociatedObjectHandle) as? String ?? "" }
quelle
UInt8
kommt aus dem verlinkten Original-Thread.Die Lösung unterstützt alle Werttypen als auch, und nicht nur jene, die automatisch überbrücken, wie String, Int, Double usw.
Wrapper
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 } }
Eine mögliche Klassenerweiterung (Anwendungsbeispiel)
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) } } } }
quelle
Any
stattdessen verwendet. Ich werde einen Blog-Artikel darüber machen, denke ichDies funktioniert natürlich nur mit Objective-C-Objekten. Nachdem Sie ein wenig damit herumgespielt haben, gehen Sie wie folgt vor, um die Anrufe in Swift zu tätigen:
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) }
quelle
Update in Swift 3.0 Dies ist beispielsweise ein 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) } } }
quelle
Klaas antwortet nur für 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
quelle
Ich habe einen modernen Helfer geschrieben, der Swift 5.1 benötigt.
/* AssociatedObject.swift Copyright © 2020 RFUI. https://github.com/BB9z/iOS-Project-Template The MIT License https://opensource.org/licenses/MIT */ import Foundation /** Objective-C associated value wrapper. Usage ``` private let fooAssociation = AssociatedObject<String>() extension SomeObject { var foo: String? { get { fooAssociation[self] } set { fooAssociation[self] = newValue } } } ``` */ public final class AssociatedObject<T> { private let policy: objc_AssociationPolicy /// Creates an associated value wrapper. /// - Parameter policy: The policy for the association. public init(policy: objc_AssociationPolicy = .OBJC_ASSOCIATION_RETAIN_NONATOMIC) { self.policy = policy } /// Accesses the associated value. /// - Parameter index: The source object for the association. public subscript(index: AnyObject) -> T? { get { objc_getAssociatedObject(index, Unmanaged.passUnretained(self).toOpaque()) as? T } set { objc_setAssociatedObject(index, Unmanaged.passUnretained(self).toOpaque(), newValue, policy) } } }
Sie werden überrascht sein, dass es sogar Swift-Strukturen kostenlos unterstützt.
quelle
Fügen Sie einfach
#import <objc/runtime.h>
auf Ihre brindging Header - Datei für den Zugriff objc_setAssociatedObject unter SWIFT - Codequelle
import ObjectiveC
in SwiftDer oben genannte Freund hat Ihre Frage beantwortet, aber wenn es sich um Verschlusseigenschaften handelt, beachten Sie bitte:
`` `
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 }
`` `
quelle