有没有办法在Swift中设置相关对象?

aml*_*szk 76 swift

来自目标C,您可以objc_setAssociatedObject在两个对象之间调用函数以使它们维护一个引用,如果在运行时您不希望销毁对象直到其引用也被删除,这可能很方便.斯威夫特有什么类似的东西吗?

Kla*_*aas 120

这是一个简单但完整的例子,源自jckarter的答案.

它显示了如何将新属性添加到现有类.它通过在扩展块中定义计算属性来实现.computed属性存储为关联对象:

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)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:

如果您需要支持获取未初始化属性的值并避免收到错误unexpectedly found nil while unwrapping an Optional value,可以像这样修改getter:

    get {
        return objc_getAssociatedObject(self, &AssociatedObjectHandle) as? String ?? ""
    }
Run Code Online (Sandbox Code Playgroud)


Hep*_*Kes 29

该解决方案也支持所有值类型,而不仅仅是那些自动桥接的类型,例如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
    }
}
Run Code Online (Sandbox Code Playgroud)

可能的 类扩展(使用示例)

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)
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这在Swift 3中变得更加容易.但无论如何,这里是基于你的答案的myarticle:http://www.yar2050.com/2016/11/associated-object-support-for-swift-23.html (5认同)

BB9*_*B9z 8

我编写了一个现代包装器,可在https://github.com/b9swift/AssociatedObject上找到

您可能会感到惊讶,它甚至免费支持 Swift 结构。

Swift 结构关联


Dar*_*ust 5

显然,这只适用于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)
}
Run Code Online (Sandbox Code Playgroud)