NSMapTable 的工作原理



我试图弄清楚NSMapTable是如何工作的所以我在操场上尝试以下代码:

class Person {
    var name: String

    init(name: String ) {
        self.name = name
        print("(name) is being initialized")
    }
    deinit {
        print("(name) is being deinitialized")
    }
}
var hobyePerson : NSMapTable? = NSMapTable<Person, NSMutableString>
(keyOptions: .weakMemory, valueOptions: .weakMemory)
var rob : Person? = Person(name: "Rob Appleseed") // print : Rob Appleseed is being initialized
hobyePerson?.setObject("golf", forKey: rob)
hobyePerson?.count // return : 1

rob = nil // print : Rob Appleseed is being deinitialized
hobyePerson?.count // return : 1 (WHY ???!!!!)

如文档中所述:"键和/或值可以选择"弱"保存,以便在回收其中一个对象时删除条目。

为什么即使我初始化了对象,以便在解除分配 rob 时它对键值对的弱引用,我在 hobyePerson 中仍然有一个元素?

当您不关心何时释放键/值时,NSMapTableweak行为选项效果最好,而是关心键/值没有被强保留,并且会在感兴趣的对象变得nil后的某个时间点释放

为什么会这样?

作为基础课程,NSMapTable的作者必须平衡功能和性能。

因此,作为性能的"优化",他们选择不会立即从地图表中删除变得nil的弱引用对象......!相反,当可以有效地完成时,这会在"以后"发生 - 例如当地图表内部调整大小时,等等。

正如@Luke在他的回答中也提到的那样,请参阅这篇关于NSMapTable行为实验的优秀文章以获取更多详细信息:

http://cocoamine.net/blog/2013/12/13/nsmaptable-and-zeroing-weak-references/

是的,这是一种奇怪而不幸的行为。本文对此进行了深入探讨。虽然它没有具体探讨弱到弱,但所描述的行为是相同的。正如该作者所指出的,hobyePerson.keyEnumerator().allObjects.counthobyePerson.objectEnumerator().allObjects.count 将包含 0,正如所有这些结束时所预期的那样。他还指出,苹果已经在Mountain Lion发行说明中记录了这种行为。

但是,目前不建议使用弱到强的 NSMapTables,因为 弱键的强值不会得到 清除(并释放),直到/除非地图表调整自身大小。

对不起,我没有更好的解释给你。

它对我不起作用,所以我实现了像这样的简单弱地图。会随着时间的推移改进它,但现在工作:

import Foundation
private struct WeakValue<Value:AnyObject> {
    weak var value: Value?
}
public class CSWeakValueDictionary<Key:AnyObject, Value:AnyObject> {
    private let dictionary = NSMutableDictionary()
    public subscript(source: Key) -> Value? {
        get {
            let value = (dictionary["(source)"] as? WeakValue<Value>)?.value
            if value == nil { dictionary.removeObject(forKey: "(source)") }
            return value
        }
        set { dictionary["(source)"] = WeakValue(value: newValue) }
    }
}

相关内容

  • 没有找到相关文章

最新更新