Skip to content

Latest commit

 

History

History
121 lines (101 loc) · 6.69 KB

源码阅读.md

File metadata and controls

121 lines (101 loc) · 6.69 KB

YYCache

简介

YYCache是一个线程安全的key-value缓存。内部使用YYMemoryCache提供了容量小,但是可快速访问的内存缓存,使用YYDiskCache提供了容量大,但是访问速度低的磁盘缓存。

YYMemoryCache

简介

  • 存储的是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做为锁.

YYDiskCache

简介

  • 线程安全的缓存
  • 存储key-value对
  • 背后是SQLite和文件系统
  • 使用LRU原则来删除对象
  • 可以针对cost, count, age设定缓存的容量
  • 可以通过配置,让缓存在没有可用磁盘空间的情况下,自动的淘汰对象
  • 可以针对每个对象,自动的决定适合的存储方式(sqlite or file),来获得更好的性能。默认情况下大于20KB就存为文件,否则存到数据库里。

作者建议自己编译最新版本的sqlite(不用libsqlite3.dylib),可以获得2到4倍的性能提升。

实现细节

  • 如果自己编译最新版本的sqlite,可以获得更好的性能
  • 为什么会针对对象的大小,设定不同的存储类型呢?因为写数据到sqlite会比外部文件要快,但是读取的性能,取决于数据的大小。对于小的数据,sqlite要更快,否则就是读文件更快了。sqlite官方也有一篇文章讲这个:sqlite读取性能分析
  • 使用dispatch_semaphore_t来做为加锁的机制。

YYKVStorage

  • 支持三种类型的存储:文件,数据库,混合。
  • 如果是数据库类型,则只会存储到数据库;文件类型会存储到文件,数据库中会存储其它信息;混合模式会根据存储对象的大小,决定存储到文件还是数据库。
  • 存储的对象的大小,是在YYDiskCache中将对象archive成NSData,根据NSData.length,可以知道对象的大小。对象必须是遵守NSCoding协议。

一些定义宏的技巧

  1. 使用__VA_ARGS__可以将...替换为实际的内容
    例如定义宏为#define TestArgs(...) __VA_ARGS__;
    使用时:TestArgs(_name = [name copy]; _study = [block copy])
    那么宏展开后就是_name = [name copy]; _study = [block copy];

SDWebImage

缓存设计

  • 实现缓存的类是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。