问题描述
我正在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.
这篇关于当一个弱引用的对象(任意类型)被释放时,我可以挂钩吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!