AFAutoPurgingImageCache:自动清理的图片缓存类
一、整体的结构:
二、重要属性:
公有的:
memoryCapacity:缓存最大在内存中占据的大小,默认100M
preferredMemoryUsageAfterPurge:进行缓存清理时期望剩余缓存图片占据的大小,默认60M
memoryUsage:以缓存的图片占据的大小私有的:
cachedImages:图片所在的集合
currentMemoryUsage:记录当前缓存图片占据的大小,公有属性memoryUsage就是读取它的值
synchronizationQueue:并行队列,对cachedImages读、写任务由该队列调度
三、主要方法
3.1存数据的方法
- (void)addImage:(UIImage *)image withIdentifier:(NSString *)identifier {
// #1:异步任务向字典集合中添加图片
dispatch_barrier_async(self.synchronizationQueue, ^{
AFCachedImage *cacheImage = [[AFCachedImage alloc] initWithImage:image identifier:identifier];
AFCachedImage *previousCachedImage = self.cachedImages[identifier];
if (previousCachedImage != nil) {//如果有同一标识的AFCachedImage存在就先减去它的大小
self.currentMemoryUsage -= previousCachedImage.totalBytes;
}
self.cachedImages[identifier] = cacheImage;
self.currentMemoryUsage += cacheImage.totalBytes;//把新添加的图片大小计算在内
});
// #2:异步任务,若#1操作后缓存总大小大于预先设定的大小,这时间顺序清楚部分缓存直到preferredMemoryUsageAfterPurge设置的大小
dispatch_barrier_async(self.synchronizationQueue, ^{
if (self.currentMemoryUsage > self.memoryCapacity) {
UInt64 bytesToPurge = self.currentMemoryUsage - self.preferredMemoryUsageAfterPurge;
NSMutableArray <AFCachedImage*> *sortedImages = [NSMutableArray arrayWithArray:self.cachedImages.allValues];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"lastAccessDate" ascending:YES];
[sortedImages sortUsingDescriptors:@[sortDescriptor]];
UInt64 bytesPurged = 0;
for (AFCachedImage *cachedImage in sortedImages) {
[self.cachedImages removeObjectForKey:cachedImage.identifier];
bytesPurged += cachedImage.totalBytes;
if (bytesPurged >= bytesToPurge) {
break ;
}
}
self.currentMemoryUsage -= bytesPurged;
}
});
}
这个方法中两次用到dispatch_barrier_async()
向并行队列中添加异步任务,这两个任务会等待队列中的其他任务执行完毕后再开始执行,就像一道“墙”一样保证了同一时刻只有一个线程执行写操作
3.2清除数据数据的方法
- (BOOL)removeImageWithIdentifier:(NSString *)identifier {
__block BOOL removed = NO;
dispatch_barrier_sync(self.synchronizationQueue, ^{
AFCachedImage *cachedImage = self.cachedImages[identifier];
if (cachedImage != nil) {
[self.cachedImages removeObjectForKey:identifier];
self.currentMemoryUsage -= cachedImage.totalBytes;
removed = YES;
}
});
return removed;
}
- (BOOL)removeAllImages {...}
清除数据也是一种写操作,所有要用barrier;又因为要以返回值的形式向外传递处理结果,所以要用sync同步操作。
3.3获取数据的方法
- (nullable UIImage *)imageWithIdentifier:(NSString *)identifier {
__block UIImage *image = nil;
dispatch_sync(self.synchronizationQueue, ^{
AFCachedImage *cachedImage = self.cachedImages[identifier];
image = [cachedImage accessImage];
});
return image;
}
同步获取数据是一种读操作,多个任务可以同时进行。如下图:
异步的写法:
- (void)imageWithIdentifier:(NSString *)identifier completion:(void (^)(UIImage *))handler {
__block UIImage *image = nil;
dispatch_async(self.synchronizationQueue, ^{
AFCachedImage *cachedImage = self.cachedImages[identifier];
image = [cachedImage accessImage];
dispatch_async(dispatch_get_main_queue(), ^{
if (handler) {
handler(image);
}
});
});
}
总结
这个类相对简单而且可以单独使用,从中可以学习到处理非线程安全的对象(这里是NSMutableDictionary)时的一些方法。