NSMutableDictionary 和 NSCache 之间处理键的不同方式(复制与保留)是否会导致不同的结果?

Does the different way of handling key between NSMutableDictionary and NSCache (copy vs. retain) result in different consequence?

我研究了NSMutableDictionaryNSCache的区别。

其中之一是 NSMutableDictionary 复制它的密钥,NSCache 只是保留它作为一个强有力的参考。

另外我发现之所以从NSMutableDictionary复制key是因为如果只保留key的话,改变key值后设置另一个值会出现奇怪的情况

        let mutableDic = NSMutableDictionary()
        var dicKey: NSString = "key"
        mutableDic.setObject("one", forKey: dicKey)
        dicKey = "changedKey"
        mutableDic.setObject("two", forKey: dicKey)

        print(mutableDic.object(forKey: "key") ?? "") //"one"
        print(mutableDic.object(forKey: "changedKey") ?? "") //"two"

但是当我使用NSCache执行相同的操作时,我感到有些奇怪。因为即使它不复制其密钥,它也能正常工作!

        let cache = NSCache<NSString, NSString>()
        var cacheKey: NSString = "key"
        cache.setObject("one", forKey: cacheKey)
        cacheKey = "changedKey"
        cache.setObject("two", forKey: cacheKey)
        print(cache.object(forKey: "key") ?? "") //"one"
        print(cache.object(forKey: "changedKey") ?? "") //"two"

所以我想知道,到底复制和保留会有什么不同的结果。

除了不需要将 NScopying 协议实现为密钥外,保留密钥而不是复制是否有任何优势?反之亦然?

能举例说明吗?

这里(ha)的关键在于对dicKey/cacheKey的赋值。具体来说,作业

dicKey = "changedKey"
cacheKey = "changedKey"

不会更改 原始 dicKeycacheKey 实例的值,而是创建新的字符串对象并将局部变量设置为指向这些实例新对象。


字典大小写:

  1. dicKey指向一个值为“key”的对象K₁
  2. mutableDic.setObject("one", forKey: dicKey)dicKey 复制到新的密钥对象 K2 中; K₁ 独自留下
  3. dicKey = "changedKey" 创建一个新的对象 K₃,值为“changedKey”,并赋值 dicKey 指向它
    • 因为没有任何东西再指向 K₁,它的引用计数变为 0,对象被释放
  4. mutableDic.setObject("two", forKey: dicKey)dicKey 复制到新的密钥对象 K₄ 中; K₂ 被单独留下

最终结果是字典中包含K2和K4,而dicKey指向K3。


缓存情况下:

  1. dicKey指向一个值为“key”的对象K₁
  2. cache.setObject("one", forKey: cacheKey) 保留 K₁ 用于插入缓存
  3. cacheKey = "changedKey" 创建一个新对象 K2,其值为“changedKey”,并赋值 cacheKey 指向它
    • 由于缓存仍然保留着 K₁,它仍然存在并在内存中,即使 dicKey 不再指向它
  4. cache.setObject("two", forKey: cacheKey) 保留 K2 用于插入缓存

最终结果是缓存中有K₁和K₂,cacheKey指向K₂。


如果不是 NSStringdicKeycacheKeyNSMutableString,其值可以在在不创建新对象的情况下运行时,您会在缓存情况下看到不同的行为:

let mutableDic = NSMutableDictionary()
var dicKey: NSMutableString = "key" // K₁
mutableDic.setObject("one", forKey: dicKey) // K₂
dicKey.setString("changedKey") // still K₁
mutableDic.setObject("two", forKey: dicKey) // K₃

print(mutableDic.object(forKey: "key") ?? "") // "one"
print(mutableDic.object(forKey: "changedKey") ?? "") // "two"

// BUT:

let cache = NSCache<NSString, NSString>()
var cacheKey: NSMutableString = "key" // K₁
cache.setObject("one", forKey: cacheKey) // still K₁
cacheKey.setString("changedKey") // still K₁
cache.setObject("two", forKey: cacheKey) // still K₁!

print(cache.object(forKey: "key") ?? "") // "" !!!
print(cache.object(forKey: "changedKey") ?? "") // "two"