Can I hook when a weakly-referenced object (of arbitrary type) is freed?

后端 未结 2 1817
暖寄归人
暖寄归人 2021-01-07 01:15

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

class WeakRefMap&         


        
2条回答
  •  谎友^
    谎友^ (楼主)
    2021-01-07 01:43

    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 {
    
        private var mapping = [Key: WeakBox]()
    
        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.

提交回复
热议问题