NSCache
NSCache 好像没有怎么经常用到过? nonono 我们常用的SDWebImage
图片下载库的缓存机制就是通过NSCache
来实现的。到底是一个什么东东呢。
An NSCache object is a collection-like container, or cache, that stores key-value pairs, similar to the NSDictionary class. Developers often incorporate caches to temporarily store objects with transient data that are expensive to create. Reusing these objects can provide performance benefits, because their values do not have to be recalculated. However, the objects are not critical to the application and can be discarded if memory is tight. If discarded, their values will have to be recomputed again when needed.
上边的话摘自Apple 文档中,大概就是说(Google 翻译的)
一个NSCache对象是一个集合状容器,或高速缓存,存储键值对,类似的NSDictionary类。开发人员通常包括缓存来暂时存放与瞬态数据是昂贵创建对象。重用这些对象可以提供性能优势,因为它们的值不必重新计算做。但是,对象不是对应用非常关键,如果内存资源紧张,可以丢弃。如果丢弃,在需要时它们的值将必须再次重新计算
当一个key-value
对在缓存中时,缓存维护它的一个强引用。存储在NSCache
中的通用数据类型通常是实现了NSDiscardableContent
协议的对象。在缓存中存储这类对象是有好处的,因为当不再需要它时,可以丢弃这些内容,以节省内存。默认情况下,缓存中的NSDiscardableContent
对象在其内容被丢弃时,会被移除出缓存,尽管我们可以改变这种缓存策略。如果一个NSDiscardableContent
被放进缓存,则在对象被移除时,缓存会调用discardContentIfPossible
方法。
NSCache 与 可变的集合有几点不同
NSCache
类结合了各种自动删除策略,以确保不会占用过多的系统内存。如果其它应用需要内存时,系统自动执行这些策略。当调用这些策略时,会从缓存中删除一些对象,以最大限度减少内存的占用。NSCache
是线程安全的,我们可以在不同的线程中添加、删除和查询缓存中的对象,而不需要锁定缓存区域。不像
NSMutableDictionary
对象,一个缓存对象不会拷贝key
对象。这些特性对于
NSCache
类来说是必须的,因为在需要释放内存时,缓存必须异步地在幕后决定去自动修改自身。
上边的这一大段话都是来自文档,大概了解之后就是说,NSCache 对缓存有很高效的性能。
使用
我们也来做一个简单的图片缓存机制吧。
class ImgeLoader {
let cache = NSCache()
static let shareInstance = ImgeLoader()
private init(){}
func imgeForURL(urlString: String, completionHander: (image: UIImage?,url:String) -> Void) {
//异步获取图片
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) {
let cacheData = self.cache.objectForKey(urlString) as? NSData
if let goodData = cacheData {
let imge = UIImage(data: goodData)
//返回主线程
dispatch_async(dispatch_get_main_queue(), {
completionHander(image: imge,url: urlString)
})
}
//如果没有图片则网络获取
let session = NSURLSession.sharedSession()
let url = NSURL(string: urlString)
let downloadTask = session.dataTaskWithURL(url!, completionHandler: { (data, res, error) in
guard error == nil && data != nil else {
completionHander(image: nil,url: urlString)
return
}
let image = UIImage(data: data!)
self.cache.setObject(data!, forKey: urlString)
dispatch_async(dispatch_get_main_queue(), {
completionHander(image: image, url: urlString)
})
})
downloadTask.resume()
}
}
}