Generics 将Swift对象与NSObject实例关联

Generics 将Swift对象与NSObject实例关联,generics,swift,nsobject,Generics,Swift,Nsobject,我希望通过扩展将Swift事物(泛型、结构、元组、Objective-C不喜欢的任何东西)与NSObject实例关联起来 我们今天怎么能做到这一点objc_setassociated object对于处理Swift功能没有任何用处 我的第一种方法是使用带有弱键的全局字典来存储关联。比如: struct WeakKey<T where T: NSObject> : Hashable { weak var object : T! init (object: T) {

我希望通过扩展将Swift事物(泛型、结构、元组、Objective-C不喜欢的任何东西)与NSObject实例关联起来

我们今天怎么能做到这一点
objc_setassociated object
对于处理Swift功能没有任何用处

我的第一种方法是使用带有弱键的全局字典来存储关联。比如:

struct WeakKey<T where T: NSObject> : Hashable {
    weak var object : T!

    init (object: T) {
        self.object = object
    }

    var hashValue: Int { return self.object.hashValue  }
}

func ==<T where T: NSObject>(lhs: WeakKey<T>, rhs: WeakKey<T>) -> Bool {
    return lhs.object == rhs.object
}

typealias ThingObjcDoesntLike = (Int, String)

var _associations : [WeakKey<NSObject>: ThingObjcDoesntLike] = [:]

extension NSObject {

    var associatedThing : ThingObjcDoesntLike! {
        get {
            let key = WeakKey(object: self)
            return _associations[key]
        }
        set(thing) {
            let key = WeakKey(object: self)
            _associations[key] = thing
        }
    }

}

let o = NSObject()
let t = (1, "Hello World")
o.associatedThing = t
struct WeakKey:Hashable{
弱var对象:T!
init(对象:T){
self.object=对象
}
var hashValue:Int{return self.object.hashValue}
}
func==(左:威基,右:威基)->Bool{
返回lhs.object==rhs.object
}
typealias ThingObjcDoesntLike=(Int,String)
变量关联:[WeakKey:ThingObjcDoesntLike]=[:]
扩展NSObject{
var AssociatedThingObjcDoesntlike{
得到{
让key=WeakKey(对象:self)
返回_关联[键]
}
设置(事物){
让key=WeakKey(对象:self)
_联想[关键]=事物
}
}
}
设o=NSObject()
设t=(1,“你好,世界”)
o、 关联事物=t
不幸的是,这会在
\u关联
声明中的
EXC\u BAD\u访问
时崩溃。删除
可以解决崩溃问题,但会导致保留NSObject实例


为了实现这一点,当NSObject被解除锁定时,我们还应将关联设置为
nil
。我们可以使用关联的见证对象进行此操作,并覆盖其解除锁定来完成此工作。为了简单起见,我在上面的代码中省略了这一点

像这样的东西怎么样:

class ObjectWrapper : NSObject {
    let value: ThingObjcDoesntLike

    init(value: ThingObjcDoesntLike) {
       self.value = value
    }
}

extension NSObject {

    var associatedThing : ThingObjcDoesntLike! {
        get {
            let wrapper = objc_getAssociatedObject(self, someKey) as ObjectWrapper?
            return wrapper?.value
        }
        set(value) {
            let wrapper = ObjectWrapper(value: value)
            objc_setAssociatedObject(self, someKey, wrapper, UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC))
        }
    }    
}
@尼克洛克伍德的答案应该是正确的。然而,当使用他的方法时,我开始在运行时遇到奇怪的内存异常。这可能是另一回事,但当我尝试另一种方法时,问题消失了。我们必须进一步挖掘

以下是我在操场上的表现。我之所以发布它,是因为它看起来很有效,而且我觉得代码很有趣,即使它最终不是最好的解决方案

我正在使用一个全局Swift
字典
,指针作为弱键。为了清除字典,我使用了一个与见证关联的对象,该对象通过
deinit
上的关联回调该对象

import Foundation
import ObjectiveC

var _associations : [COpaquePointer: Any] = [:]

@objc protocol HasAssociatedSwift : class {

    func clearSwiftAssociations()
}

var _DeinitWitnessKey: UInt8 = 0

class DeinitWitness : NSObject {

    weak var object : HasAssociatedSwift!

    init (object: HasAssociatedSwift) {
        self.object = object
    }

    deinit {
        object.clearSwiftAssociations()
    }

    class func addToObject(object : NSObject) {
        var witness = objc_getAssociatedObject(object, &_DeinitWitnessKey) as DeinitWitness?
        if (witness == nil) {
            witness = DeinitWitness(object: object)
            objc_setAssociatedObject(object, &_DeinitWitnessKey, witness, UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC))
        }
    }
}

extension NSObject : HasAssociatedSwift {

    var associatedThing : Any! {
        get {
            return _associations[self.opaquePointer]
        }
        set(thing) {
            DeinitWitness.addToObject(self)
            _associations[self.opaquePointer] = thing
        }
    }

    var opaquePointer : COpaquePointer {
        return Unmanaged<AnyObject>.passUnretained(self).toOpaque()
    }

    func clearSwiftAssociations() {
        _associations[self.opaquePointer] = nil
    }
}

let o = NSObject()
o.associatedThing = (1, "Hello")
<代码>导入基础 导入对象 变量关联:[COpaquePointer:Any]=[:] @objc协议已关联SWIFT:类{ func清除WiftAssociations() } var_DenithWitnessKey:UInt8=0 类DenitWitness:NSObject{ 弱变量对象:hassociatedSwift! init(对象:HasAssociatedSwift){ self.object=对象 } 脱硝{ object.ClearWiftAssociations() } 类func addToObject(对象:NSObject){ var-witness=objc_getAssociatedObject(对象,&_DeinitWitnessKey)作为DeinitWitness? 如果(证人==无){ 见证=取消见证(对象:对象) objc_setAssociatedObject(对象和DeinitWitnessKey、见证、UInt(objc_关联、保留、非原子)) } } } 扩展NSObject:HasAssociatedSwift{ var associatedThing:任何{ 得到{ 返回关联[self.opaquePointer] } 设置(事物){ DeinitWitness.addToObject(自) _联想[self.opaquePointer]=事物 } } 变量opaquePointer:COpaquePointer{ 返回未托管的.passUnretained(self).toOpaque() } func清除WiftAssociations(){ _关联[self.opaquePointer]=nil } } 设o=NSObject() o、 associatedThing=(1,“你好”)
谢谢你,尼克!这似乎是可行的,但是有没有保证
objc_setassociated object
可以正确处理和管理包装的纯Swift构造(超级结构、泛型等)的内存?不必。它只担心保留/释放容器对象(遵循正常的objc约定)。容器管理其内部构造的内存。它似乎比它看起来更重要。当使用这个时,我开始出现奇怪的内存错误。我最后做了一些我稍后会发布的事情。
ObjectWrapper
不需要子类
NSObject
@newacct一点也不需要,您只需要让ObjectWrapper接受泛型类型