深入源码理解YYCache 、SDWebImage、AFNetworking、NSCache 缓存方式与对比
转载请注明出处 http://blog.csdn.net/u014205968/article/details/78490145
在之前的一篇文章iOS缓存 NSCache详解及SDWebImage缓存策略源码分析中详细讲解了NSCache
的用法以及SDWebImage
内存和磁盘缓存的源码分析,本篇文章将简要讲解AFNetworking
缓存类和YYCache
并作出对比。
由于之前的一篇文章已经详细讲解了NSCache
和SDWebImage
缓存策略,本篇文章不再赘述,会简要介绍一下AFNetworking
和YYCache
的源码。
AFNetworking图片缓存AFAutoPurgingImageCache
AFNetworking
也提供了同SDWebImage
一样的下载图片的功能,也提供了缓存这些图片的功能,但它只提供了内存缓存,没有提供磁盘缓存功能。
看一下头文件:
//缓存协议,如果用户需要实现自定义的
@protocol AFImageCache <NSObject>
//添加图片并传递一个唯一id,一般使用图片的URL
- (void)addImage:(UIImage *)image withIdentifier:(NSString *)identifier;
//删除id为identifier的图片
- (BOOL)removeImageWithIdentifier:(NSString *)identifier;
//删除所有缓存图片
- (BOOL)removeAllImages;
//根据id获取图片
- (nullable UIImage *)imageWithIdentifier:(NSString *)identifier;
@end
//AFImageRequestCache协议,继承AFImageCache协议
@protocol AFImageRequestCache <AFImageCache>
//添加图片,传入下载图片的request和额外的id
- (void)addImage:(UIImage *)image forRequest:(NSURLRequest *)request withAdditionalIdentifier:(nullable NSString *)identifier;
//删除图片,传入下载图片的request和额外的id
- (BOOL)removeImageforRequest:(NSURLRequest *)request withAdditionalIdentifier:(nullable NSString *)identifier;
//根据下载图片的request和额外的id获取图片
- (nullable UIImage *)imageforRequest:(NSURLRequest *)request withAdditionalIdentifier:(nullable NSString *)identifier;
@end
//AFNetworking提供的缓存类,
@interface AFAutoPurgingImageCache : NSObject <AFImageRequestCache>
//单位是字节,能够支持最大缓存大小
@property (nonatomic, assign) UInt64 memoryCapacity;
//建议的当内存缓存要释放的时候需要释放到多大的大小
@property (nonatomic, assign) UInt64 preferredMemoryUsageAfterPurge;
//当前内存缓存占用的字节大小
@property (nonatomic, assign, readonly) UInt64 memoryUsage;
//构造函数
- (instancetype)init;
//构造函数
- (instancetype)initWithMemoryCapacity:(UInt64)memoryCapacity preferredMemoryCapacity:(UInt64)preferredMemoryCapacity;
@end
从头文件可以看出,AFNetworking
提供的AFAutoPurgingImageCache
接口不多,而且都很简单,只实现了内存缓存的功能。
看一下实现文件:
//缓存对象包装类
@interface AFCachedImage : NSObject
//缓存的图片
@property (nonatomic, strong) UIImage *image;
//id
@property (nonatomic, strong) NSString *identifier;
//图片字节大小
@property (nonatomic, assign) UInt64 totalBytes;
//淘汰算法是LRU所以需要记录上次访问时间
@property (nonatomic, strong) NSDate *lastAccessDate;
//没用到的属性
@property (nonatomic, assign) UInt64 currentMemoryUsage;
@end
@implementation AFCachedImage
//初始化构函数
-(instancetype)initWithImage:(UIImage *)image identifier:(NSString *)identifier {
if (self = [self init]) {
self.image = image;
self.identifier = identifier;
//计算图片的字节大小,每个像素占4字节32位
CGSize imageSize = CGSizeMake(image.size.width * image.scale, image.size.height * image.scale);
CGFloat bytesPerPixel = 4.0;
CGFloat bytesPerSize = imageSize.width * imageSize.height;
self.totalBytes = (UInt64)bytesPerPixel * (UInt64)bytesPerSize;
self.lastAccessDate = [NSDate date];
}
return self;
}
//通过缓存对象获取图片时要更新上次访问时间为当前时间
- (UIImage*)accessImage {
//直接使用NSDate
self.lastAccessDate = [NSDate date];
return self.image;
}
- (NSString *)description {
NSString *descriptionString = [NSString stringWithFormat:@"Idenfitier: %@ lastAccessDate: %@ ", self.identifier, self.lastAccessDate];
return descriptionString;
}
@end
//AFNetworking缓存类的猪脚
@interface AFAutoPurgingImageCache ()
//可变字典用于存储所有的缓存对象AFCachedImage对象,key为字符串类型
@property (nonatomic, strong) NSMutableDictionary <NSString* , AFCachedImage*> *cachedImages;
//当前缓存对象内存占用大小
@property (nonatomic, assign) UInt64 currentMemoryUsage;
//用于线程安全防止产生竞争条件,没有用锁
@property (nonatomic, strong) dispatch_queue_t synchronizationQueue;
@end
@implementation AFAutoPurgingImageCache
//构造函数,默认内存占用100M,每次清除缓存到60M
- (instancetype)init {
return [self initWithMemoryCapacity:100 * 1024 * 1024 preferredMemoryCapacity:60 * 1024 * 1024];
}
//构造函数
- (instancetype)initWithMemoryCapacity:(UInt64)memoryCapacity preferredMemoryCapacity:(UInt64)preferredMemoryCapacity {
if (self = [super init]) {
self.memoryCapacity = memoryCapacity;
self.preferredMemoryUsageAfterPurge = preferredMemoryCapacity;
self.cachedImages = [[NSMutableDictionary alloc] init];
//创建一个并行队列,但后面使用时都是在同步情况或barrier情况下,队列中的任务还是以串行执行
//可以防止产生竞争条件,保证线程安全
NSString *queueName = [NSString stringWithFormat:@"com.alamofire.autopurgingimagecache-%@", [[NSUUID UUID] UUIDString]];
self.synchronizationQueue = dispatch_queue_create([queueName cStringUsingEncoding:NSASCIIStringEncoding], DISPATCH_QUEUE_CONCURRENT);
//添加通知,监听收到系统的内存警告后删除所有缓存对象
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(removeAllImages)
name:UIApplicationDidReceiveMemoryWarningNotification
object:nil];
}
return self;
}
//析构函数,删除通知的监听
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
//memoryUsage的getter
- (UInt64)memoryUsage {
__block UInt64 result = 0;
dispatch_sync(self.synchronizationQueue, ^{
result = self.currentMemoryUsage;