我研究了NSMutableDictionary
和NSCache
的差异。
其中一个是NSMutableDictionary
复制它的key,而NSCache
只保留它作为一个强引用。
另外,我发现之所以从NSMutableDictionary
复制密钥,是因为如果只保留密钥,在更改密钥值后设置另一个值时会出现奇怪的情况。
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"
不改变原始dicKey
和cacheKey
实例的值,而是创建新的字符串对象并设置局部变量指向这些新对象。
在字典的情况下:
dicKey
指向值为"key"的对象K₁mutableDic.setObject("one", forKey: dicKey)
将dicKey
复制到一个新的key对象K₂中;K₁单独保留dicKey = "changedKey"
创建一个值为"changedkey"的新对象K₃,并指定dicKey
指向它- 由于不再指向K₁,其引用计数变为0,对象被释放
mutableDic.setObject("two", forKey: dicKey)
复制dicKey
到一个新的key对象K₄;K₂被单独保留
最终结果是字典包含K₂和K₄,而dicKey
指向K₃。
在缓存的情况下:
dicKey
指向值为"key"的对象K₁cache.setObject("one", forKey: cacheKey)
保留K₁以插入缓存cacheKey = "changedKey"
创建一个新对象K₂,其值为"changedKey"并赋值cacheKey
指向它- 由于缓存仍然保留K₁,因此即使
dicKey
不再指向它,它仍保持活动并在内存中
- 由于缓存仍然保留K₁,因此即使
cache.setObject("two", forKey: cacheKey)
保留K₂用于插入缓存
最终结果是缓存包含K₁和K₂,cacheKey
指向K₂。
如果dicKey
和cacheKey
不是NSString
,而是NSMutableString
,其值可以在运行时修改而无需创建新对象,那么在缓存情况下您将看到不同的行为:
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"