可怜的 NSCache 一直处于 NSMutableDictionary 的阴影之下。就好像没有人知道它提供了垃圾处理的功能,而开发者们却费劲力气地去自己实现它。
没错,NSCache 基本上就是一个会自动移除对象来释放内存的 NSMutableDictionary。无需响应内存警告或者使用计时器来清除缓存。唯一的不同之处是键对象不会像 NSMutableDictionary 中那样被复制,这实际上是它的一个优点(键不需要实现 NSCopying 协议)。
如果开发者们知道就好了……
但是,你并不像其他开发者那样,对吧?你应该不会小看 NSCache 的?
这并不是说它没有一丝瑕疵和一些莫名其妙的问题。NSCache 就像是个烫手山芋。
拿 setObject:forKey:cost: 来说,它和 setObject:forKey: 方法类似,但是带着 cost 参数。你可能会问,那是个什么东西?好吧,官方文档甚至都没有说清楚:
cost 被用来计算缓存中所有对象的代价。当内存受限或者所有缓存对象的总代价超过了最大允许的值时,缓存会移除其中的一些对象。
很好,目前为止还不错……
然而,这个移除流程并不会保证顺序。后果就是,如果你期望通过控制 cost 的值来完成某些特殊行为的话,结果可能会对你的程序无益。
啊?这是什么意思?
通常,精确的 cost 应该是对象占用的字节数。如果它不可以直接读出来的话,你没必要费劲地去计算它,因为这么做的话会增加使用缓存的代价。
等会儿,那不精确的 cost 值应该怎么计算呢?有什么计算内存占用的规则吗?比如按数量排序来计算?“随便瞎猜导致性能变差”似乎不会让人满意……
如果你没有有效的值传入,那就传入 0,或者用 setObject:forKey: 方法,它不需要传入 cost 值。
懂了:除非你在 Apple 工作并且认识写这个类的人,否则不要用这个方法。
另外,它还有一套使用 evictsObjectsWithDiscardedContent 和 <NSDiscardableContent> 来控制对象是否会被自动移除的机制,但是这可能只会让你碰到更多的问题。
尽管有上面提到的这些问题,开发者们还是应该多多使用 NSCache。你项目中任何你称之为缓存却不是 NSCache 对象的东西都应该被换成 NSCache。但是,如果你这么做了,务必要用你熟悉的那套 objectForKey:、setObject:forKey:、removeObjectForKey: 方法。