圖解AFNetworking中提供的圖片緩存類

AFAutoPurgingImageCache:自動清理的圖片緩存類

一、整體的結(jié)構(gòu):

綠色公有、黃色私有

二、重要屬性:

  • 公有的:
    memoryCapacity:緩存最大在內(nèi)存中占據(jù)的大小,默認(rèn)100M
    preferredMemoryUsageAfterPurge:進行緩存清理時期望剩余緩存圖片占據(jù)的大小,默認(rèn)60M
    memoryUsage:以緩存的圖片占據(jù)的大小

  • 私有的:
    cachedImages:圖片所在的集合
    currentMemoryUsage:記錄當(dāng)前緩存圖片占據(jù)的大小,公有屬性memoryUsage就是讀取它的值
    synchronizationQueue:并行隊列,對cachedImages讀、寫任務(wù)由該隊列調(diào)度

三、主要方法

3.1存數(shù)據(jù)的方法
- (void)addImage:(UIImage *)image withIdentifier:(NSString *)identifier {
     // #1:異步任務(wù)向字典集合中添加圖片
    dispatch_barrier_async(self.synchronizationQueue, ^{
        AFCachedImage *cacheImage = [[AFCachedImage alloc] initWithImage:image identifier:identifier];
        AFCachedImage *previousCachedImage = self.cachedImages[identifier];
        if (previousCachedImage != nil) {//如果有同一標(biāo)識的AFCachedImage存在就先減去它的大小
            self.currentMemoryUsage -= previousCachedImage.totalBytes;
        }
        self.cachedImages[identifier] = cacheImage;
        self.currentMemoryUsage += cacheImage.totalBytes;//把新添加的圖片大小計算在內(nèi)
    });
    // #2:異步任務(wù),若#1操作后緩存總大小大于預(yù)先設(shè)定的大小,這時間順序清楚部分緩存直到preferredMemoryUsageAfterPurge設(shè)置的大小
    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()向并行隊列中添加異步任務(wù),這兩個任務(wù)會等待隊列中的其他任務(wù)執(zhí)行完畢后再開始執(zhí)行,就像一道“墻”一樣保證了同一時刻只有一個線程執(zhí)行寫操作

3.2清除數(shù)據(jù)數(shù)據(jù)的方法
- (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ù)據(jù)也是一種寫操作,所有要用barrier;又因為要以返回值的形式向外傳遞處理結(jié)果,所以要用sync同步操作。

3.3獲取數(shù)據(jù)的方法
- (nullable UIImage *)imageWithIdentifier:(NSString *)identifier {
    __block UIImage *image = nil;
    dispatch_sync(self.synchronizationQueue, ^{
        AFCachedImage *cachedImage = self.cachedImages[identifier];
        image = [cachedImage accessImage];
    });
    return image;
}

同步獲取數(shù)據(jù)是一種讀操作,多個任務(wù)可以同時進行。如下圖:

異步的寫法:

- (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);
            }
        });
    });
}

總結(jié)

這個類相對簡單而且可以單獨使用,從中可以學(xué)習(xí)到處理非線程安全的對象(這里是NSMutableDictionary)時的一些方法。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容