AFAutoPurgingImageCache:自動清理的圖片緩存類
一冗酿、整體的結構:
綠色公有画拾、黃色私有
二熟菲、重要屬性:
公有的:
memoryCapacity:緩存最大在內存中占據的大小朋贬,默認100M
preferredMemoryUsageAfterPurge:進行緩存清理時期望剩余緩存圖片占據的大小椭更,默認60M
memoryUsage:以緩存的圖片占據的大小私有的:
cachedImages:圖片所在的集合
currentMemoryUsage:記錄當前緩存圖片占據的大小,公有屬性memoryUsage就是讀取它的值
synchronizationQueue:并行隊列饶深,對cachedImages讀婿滓、寫任務由該隊列調度
三、主要方法
3.1存數(shù)據的方法
- (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()
向并行隊列中添加異步任務橘券,這兩個任務會等待隊列中的其他任務執(zhí)行完畢后再開始執(zhí)行额湘,就像一道“墻”一樣保證了同一時刻只有一個線程執(zhí)行寫操作
3.2清除數(shù)據數(shù)據的方法
- (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 {...}
清除數(shù)據也是一種寫操作,所有要用barrier旁舰;又因為要以返回值的形式向外傳遞處理結果锋华,所以要用sync同步操作。
3.3獲取數(shù)據的方法
- (nullable UIImage *)imageWithIdentifier:(NSString *)identifier {
__block UIImage *image = nil;
dispatch_sync(self.synchronizationQueue, ^{
AFCachedImage *cachedImage = self.cachedImages[identifier];
image = [cachedImage accessImage];
});
return image;
}
同步獲取數(shù)據是一種讀操作箭窜,多個任務可以同時進行毯焕。如下圖:
異步的寫法:
- (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)時的一些方法磺樱。