YYCache是一个线程安全的key-value缓存。内部使用YYMemoryCache提供了容量小,但是可快速访问的内存缓存,使用YYDiskCache提供了容量大,但是访问速度低的磁盘缓存。
- 存储的是key-value对。
- 与NSDictionary相比,keys被retain,而不是copy。NSDictionary的key,要符合NSCopying协议。
- 使用LRU(least-recently-used)算法删除对象;NSCache的淘汰方法是不确定的。
- 可以根据cost, count and age来控制缓存;NSCache的限制是不精确的。
- 可以通过配置,让缓存在收到内存告警或是应用进入后台后,自动的淘汰缓存里的对象。
- 访问方法的时间复杂度是O(1)
- 使用了一个双向链表,每个结点里会存储key, value,链表的头部结点是使用次数最多的,尾部结点是使用次数最少的。结点作为value同时存储在CFDictionary中,key是node->key。
- 使用了
pthread_mutex_lock
做为锁.
- 线程安全的缓存
- 存储key-value对
- 背后是SQLite和文件系统
- 使用LRU原则来删除对象
- 可以针对cost, count, age设定缓存的容量
- 可以通过配置,让缓存在没有可用磁盘空间的情况下,自动的淘汰对象
- 可以针对每个对象,自动的决定适合的存储方式(sqlite or file),来获得更好的性能。默认情况下大于20KB就存为文件,否则存到数据库里。
作者建议自己编译最新版本的sqlite(不用libsqlite3.dylib),可以获得2到4倍的性能提升。
- 如果自己编译最新版本的sqlite,可以获得更好的性能
- 为什么会针对对象的大小,设定不同的存储类型呢?因为写数据到sqlite会比外部文件要快,但是读取的性能,取决于数据的大小。对于小的数据,sqlite要更快,否则就是读文件更快了。sqlite官方也有一篇文章讲这个:sqlite读取性能分析
- 使用
dispatch_semaphore_t
来做为加锁的机制。
- 支持三种类型的存储:文件,数据库,混合。
- 如果是数据库类型,则只会存储到数据库;文件类型会存储到文件,数据库中会存储其它信息;混合模式会根据存储对象的大小,决定存储到文件还是数据库。
- 存储的对象的大小,是在YYDiskCache中将对象archive成NSData,根据NSData.length,可以知道对象的大小。对象必须是遵守NSCoding协议。
- 使用
__VA_ARGS__
可以将...
替换为实际的内容
例如定义宏为#define TestArgs(...) __VA_ARGS__;
使用时:TestArgs(_name = [name copy]; _study = [block copy])
那么宏展开后就是_name = [name copy]; _study = [block copy];
- 实现缓存的类是SDImageCache,它维护了一个内存缓存,以及一个磁盘缓存。磁盘缓存的写操作是异步执行的,这样可以避免UI卡顿。
- 内存缓存是用NSCache做的,派生了一个类叫AutoPurgeCache,会注册UIApplicationDidReceiveMemoryWarningNotification这个通知。收到通知时,会调用removeAllObjects方法。
- 调用[NSFileManager new]生成了一个file manager的实例,在实现中用到file manager的地方,都是使用这个实例。
- 禁止iCloud备份
NSURL *fileURL = [NSURL fileURLWithPath:cachePathForKey];
[fileURL setResourceValue:@YES forKey:NSURLIsExcludedFromBackupKey error:nil];
-
缓存到磁盘的文件名,是根据原始的图片链接地址,生成一个MD5(16字节),然后格式化一个字符串(以16进制的形式)。
-
NSURL有
setResourceValue:forKey:error:
和getResourceValue:forKey:error:
方法,可以设置或获取一些key对应的值,对于文件类型的URL很有用。 -
NSFileManager有enumeratorAtURL / enumeratorAtPath 方法,很强大,可以指定获取哪些属性,是否跳过隐藏文件。在遍历一个目录时很好用。
-
SDImageCache注册了三个通知:
UIApplicationDidReceiveMemoryWarningNotification: 收到这个通知时会去清除内存缓存。
UIApplicationWillTerminateNotification: 收到这个通知时会去删除磁盘上的旧文件。
UIApplicationDidEnterBackgroundNotification:收到这个通知时,会去在后台清除磁盘上的老文件。由于用时可能比较长,那么需要申请额外的后台执行时间。UIApplication *application = [UIApplication performSelector:@selector(sharedApplication)]; __block UIBackgroundTaskIdentifier bgTask = [application beginBackgroundTaskWithExpirationHandler:^{ // Clean up any unfinished task business by marking where you // stopped or ending the task outright. [application endBackgroundTask:bgTask]; bgTask = UIBackgroundTaskInvalid; }]; // Start the long-running task and return immediately. [self deleteOldFilesWithCompletionBlock:^{ [application endBackgroundTask:bgTask]; bgTask = UIBackgroundTaskInvalid; }];
- SDWebImageManager
我们平常直接对UIImageView或是UIButton这些类使用图片异步加载的方法,但它的背后是SDWebImageManager这个核心类。它将异步图片下载器和图片缓存进行关联,我们也可以直接使用。
SDWebImageManager *manager = [SDWebImageManager sharedManager];
[manager loadImageWithURL:imageURL
options:0
progress:^(NSInteger receivedSize, NSInteger expectedSize) {
// progression tracking code
}
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
if (image) {
// do something with image
}
}];
-
SDWebImageDownloader 负责图片异步下载的类,可以单独使用。
SDWebImageDownloader *downloader = [SDWebImageDownloader sharedDownloader];
[downloader downloadImageWithURL:imageURL options:0 progress:^(NSInteger receivedSize, NSInteger expectedSize) { // progression tracking code } completed:^(UIImage *image, NSData *data, NSError *error, BOOL finished) { if (image && finished) { // do something with image } }];
* SDWebImageCache
这个类提供了一个单例,用来创建缺省的缓存。除此之外,我们也可以创建额外的实例,并指定不同的namespace。