Исходя из цели C, вы можете вызывать функцию objc_setAssociatedObject
между двумя объектами, чтобы они поддерживали ссылку, что может быть удобно, если во время выполнения вы не хотите, чтобы объект был уничтожен, пока его ссылка также не будет удалена. Есть ли у Swift что-нибудь подобное?
82
objc_setAssociatedObject
Swift: developer.apple.com/library/prerelease/ios/documentation/Swift/…Ответы:
Вот простой, но полный пример, полученный из ответа jckarter .
Он показывает, как добавить новое свойство к существующему классу. Это достигается путем определения вычисляемого свойства в блоке расширения. Вычисленное свойство сохраняется как связанный объект:
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) } } }
РЕДАКТИРОВАТЬ:
Если вам нужно поддерживать получение значения неинициализированного свойства и избежать ошибки
unexpectedly found nil while unwrapping an Optional value
, вы можете изменить метод получения следующим образом:get { return objc_getAssociatedObject(self, &AssociatedObjectHandle) as? String ?? "" }
источник
UInt8
происходит из связанной исходной цепочки.Решение также поддерживает все типы значений , а не только те, которые автоматически соединяются мостом, такие как String, Int, Double и т. Д.
Обертки
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 } }
Возможное расширение класса (пример использования)
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) } } } }
источник
Any
вместо них. Думаю, яОчевидно, это работает только с объектами Objective-C. Немного поработав с этим, вот как выполнять вызовы в 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) }
источник
Обновление в Swift 3.0 Например, это 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) } } }
источник
Я написал современный помощник, для которого требуется Swift 5.1.
/* 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) } } }
Вы можете быть удивлены тем, что он даже бесплатно поддерживает структуры Swift.
источник
Клаас отвечает только для 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
источник
Просто добавьте
#import <objc/runtime.h>
заголовочный файл brindging, чтобы получить доступ к objc_setAssociatedObject под быстрым кодомисточник
import ObjectiveC
в SwiftВышеупомянутый друг ответил на ваш вопрос, но если он связан со свойствами закрытия, обратите внимание:
``
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 }
``
источник