当一个弱引用的对象(任意类型)被释放时,我可以挂钩吗? [英] Can I hook when a weakly-referenced object (of arbitrary type) is freed?

查看:114
本文介绍了当一个弱引用的对象(任意类型)被释放时,我可以挂钩吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在Swift中编写一个容器类,它在Java中的工作方式类似于 java.util.WeakHashMap 。我目前的实现是在这里。

 类WeakRefMap< Key:Hashable,Value:AnyObject> {

private var mapping = [Key:WeakBox< Value>]()

subscript(key:Key) - >值? {
get {return mapping [key] ?. raw}
set {
if let o = newValue {
mapping [key] = WeakBox(o)
}
else {
mapping.removeValueForKey(key)
}
}
}

var count:Int {return mapping.count}
}

class WeakBox< E:AnyObject> {
weak var raw:E!
init(_ raw:E){self.raw = raw}
}

在这个实现中,通过 WeakBox 弱引用容器中的对象,所以保持值不会阻止在不再需要时释放对象。



但是这个代码显然有一个问题;即使在条目对象被释放之后,这些条目仍然保留。



为了解决这个问题,我需要在释放被保持的对象之前钩住它,并删除它)条目。我只知道解决方案仅适用于 NSObject ,但它不适用于 AnyObject



有人可以帮我吗?谢谢。 (^ _ ^)

解决方案

可悲的是, didSet code> willSet 观察者在 weak var raw 属性值被释放时不会调用。


$在这种情况下,您必须使用 objc_setAssociatedObject

  // helper类来通知deallocation 
class DeallocWatcher {
let notify:() - > Void
init(_ notify:() - > Void){self。 notify = notify}
deinit {notify()}
}

class WeakRefMap< Key:Hashable,Value:AnyObject> {

private var mapping = [Key:WeakBox< Value>]()

subscript(key:Key) - >值? {
get {return mapping [key] ?. raw}
set {
if let o = newValue {
//添加帮助器到关联对象。
//当`o`被释放时,`watcher`也被释放。
//所以`watcher.deinit()`将被调用。
允许观察者= deallocWatcher {[unowned self] in self.mapping [key] = nil}
objc_setAssociatedObject(o,unsafeAddressOf(self),watcher,objc_AssociationPolicy(OBJC_ASSOCIATION_RETAIN_NONATOMIC))
mapping [key ] = WeakBox(o)
}
else {
mapping [key] = nil
}
}
}

var count:Int {return mapping.count}

deinit {
// cleanup
for e in self.mapping.values {
objc_setAssociatedObject(e.raw, unsafeAddressOf(self),nil,0)
}
}
}

注意:在Swift 1.2之前。此解决方案不适用于任意Swift类。


I'm writing a container class in Swift, which works like as java.util.WeakHashMap in Java. My current implementation is here.

class WeakRefMap<Key: Hashable, Value: AnyObject> {

    private var mapping = [Key: WeakBox<Value>]()

    subscript(key: Key) -> Value? {
        get { return mapping[key]?.raw }
        set {
            if let o = newValue {
                mapping[key] = WeakBox(o)
            }
            else {
                mapping.removeValueForKey(key)
            }
        }
    }

    var count: Int { return mapping.count }
}

class WeakBox<E: AnyObject> {
    weak var raw: E!
    init(  _ raw: E) { self.raw = raw }
}

In this implementation, holded objects in the container are weakly-referenced via WeakBox, so holding values never prevents the objects from being released when not needed anymore.

But clearly there is a problem in this code; The entries remains even after the object of its entry is freed.

To solve this problem, I need to hook just before a holded object is released, and remove its (corresponding) entry. I know a solution only for NSObject, but it's not applicable to AnyObject.

Could anyone help me? Thanks. (^_^)

解决方案

Sad to say, didSet or willSet observer doesn't get called when weak var raw property value is deallocated.

So, you have to use objc_setAssociatedObject in this case:

// helper class to notify deallocation
class DeallocWatcher {
    let notify:()->Void
    init(_ notify:()->Void) { self.notify = notify }
    deinit { notify() }
}

class WeakRefMap<Key: Hashable, Value: AnyObject> {

    private var mapping = [Key: WeakBox<Value>]()

    subscript(key: Key) -> Value? {
        get { return mapping[key]?.raw }
        set {
            if let o = newValue {
                // Add helper to associated objects.
                // When `o` is deallocated, `watcher` is also deallocated.
                // So, `watcher.deinit()` will get called.
                let watcher = DeallocWatcher { [unowned self] in self.mapping[key] = nil }
                objc_setAssociatedObject(o, unsafeAddressOf(self), watcher, objc_AssociationPolicy(OBJC_ASSOCIATION_RETAIN_NONATOMIC))
                mapping[key] = WeakBox(o)
            }
            else {
                mapping[key] = nil
            }
        }
    }

    var count: Int { return mapping.count }

    deinit {
        // cleanup
        for e in self.mapping.values {
            objc_setAssociatedObject(e.raw, unsafeAddressOf(self), nil, 0)
        }
    }
}

NOTE: Before Swift 1.2. this solution does not work for arbitrary Swift classes.

这篇关于当一个弱引用的对象(任意类型)被释放时,我可以挂钩吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆