AFN 3.0學(xué)習(xí)總結(jié)(八)

參考:AFNetworking 3.0 源碼解讀(八)之 AFImageDownloader

說明:很多內(nèi)容都是摘抄原文,只是根據(jù)自己的需要進行摘抄或者總結(jié),如有不妥請及時指出,謝謝。

AFImageDownloader 這個類對寫DownloadManager有很大的借鑒意義。在平時的開發(fā)中,當我們使用UIImageView加載一個網(wǎng)絡(luò)上的圖片時,其原理就是把圖片下載下來,然后再賦值。這也是AFImageDownloader這個類的核心功能。

AFImageDownloadPrioritization

表示圖片下載的優(yōu)先級:

AFImageDownloadPrioritizationFIFO 表示先進先出
AFImageDownloadPrioritizationLIFO 表示后進先出


AFImageDownloaderMergedTask

AFImageDownloaderMergedTask 封裝了對同一個請求的處理。同下載任務(wù)一樣,也存在下載的URL重復(fù)的情況,這種情況需要做特殊處理。這里是一個值得借鑒的地方。那么如何判定是一個請求呢?AFImageDownloader是通過request.URL.absoluteString來進行判斷的。


AFImageDownloader

NSURLCache

我們簡單介紹下NSURLCache。NSURLCache 為您的應(yīng)用的 URL 請求提供了內(nèi)存中以及磁盤上的綜合緩存機制。網(wǎng)絡(luò)緩存減少了需要向服務(wù)器發(fā)送請求的次數(shù),同時也提升了離線或在低速網(wǎng)絡(luò)中使用應(yīng)用的體驗。當一個請求完成下載來自服務(wù)器的回應(yīng),一個緩存的回應(yīng)將在本地保存。下一次同一個請求再發(fā)起時,本地保存的回應(yīng)就會馬上返回,不需要連接服務(wù)器。NSURLCache 會 自動 且 透明 地返回回應(yīng)。

NSURLRequest 有個 cachePolicy 屬性,我們平時最常用的有四個屬性:

NSURLRequestUseProtocolCachePolicy: 對特定的 URL 請求使用網(wǎng)絡(luò)
協(xié)議中實現(xiàn)的緩存邏輯。這是默認的策略。
NSURLRequestReloadIgnoringLocalCacheData:數(shù)據(jù)需要從原始地址
加載。不使用現(xiàn)有緩存。
NSURLRequestReturnCacheDataElseLoad:無論緩存是否過期,先使    
用本地緩存數(shù)據(jù)。如果緩存中沒有請求所對應(yīng)的數(shù)據(jù),那么從原始地址
加載數(shù)據(jù)
NSURLRequestReturnCacheDataDontLoad:無論緩存是否過期,先使
用本地緩存數(shù)據(jù)。如果緩存中沒有請求所對應(yīng)的數(shù)據(jù),那么放棄從原始
地址加載數(shù)據(jù),請求視為失?。矗骸半x線”模式)。

核心方法

- (nullable AFImageDownloadReceipt *)downloadImageForURLRequest:(NSURLRequest *)request
                                              withReceiptID:(nonnull NSUUID *)receiptID
                                                    success:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse  * _Nullable response, UIImage *responseObject))success
                                                    failure:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, NSError *error))failure {
__block NSURLSessionDataTask *task = nil;

//判斷URLIdentifier有效性
dispatch_sync(self.synchronizationQueue, ^{
    NSString *URLIdentifier = request.URL.absoluteString;
    if (URLIdentifier == nil) {
        if (failure) {
            NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorBadURL userInfo:nil];
            dispatch_async(dispatch_get_main_queue(), ^{
                failure(request, nil, error);
            });
        }
        return;
    }

    // 1) Append the success and failure blocks to a pre-existing request if it already exists
    //根據(jù)URLIdentifier,找到已經(jīng)存在的任務(wù),把回掉與這個任務(wù)進行綁定
    AFImageDownloaderMergedTask *existingMergedTask = self.mergedTasks[URLIdentifier];
    if (existingMergedTask != nil) {
        AFImageDownloaderResponseHandler *handler = [[AFImageDownloaderResponseHandler alloc] initWithUUID:receiptID success:success failure:failure];
        [existingMergedTask addResponseHandler:handler];
        task = existingMergedTask.task;
        return;
    }

    // 2) Attempt to load the image from the image cache if the cache policy allows it
    //如果緩存策略允許,則直接讀取緩存圖片
    switch (request.cachePolicy) {
        case NSURLRequestUseProtocolCachePolicy:
        case NSURLRequestReturnCacheDataElseLoad:
        case NSURLRequestReturnCacheDataDontLoad: {
            UIImage *cachedImage = [self.imageCache imageforRequest:request withAdditionalIdentifier:nil];
            if (cachedImage != nil) {
                if (success) {
                    dispatch_async(dispatch_get_main_queue(), ^{
                        success(request, nil, cachedImage);
                    });
                }
                return;
            }
            break;
        }
        default:
            break;
    }

    // 3) Create the request and set up authentication, validation and response serialization
    //走到這一步,說明圖片還沒有找到,那么必然我們需要下載了
    //創(chuàng)建request,設(shè)置權(quán)限、序列化信息
    NSUUID *mergedTaskIdentifier = [NSUUID UUID];
    NSURLSessionDataTask *createdTask;
    __weak __typeof__(self) weakSelf = self;

    createdTask = [self.sessionManager
                   dataTaskWithRequest:request
                   uploadProgress:nil
                   downloadProgress:nil
                   completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
                       dispatch_async(self.responseQueue, ^{
                           __strong __typeof__(weakSelf) strongSelf = weakSelf;
                           
                           AFImageDownloaderMergedTask *mergedTask = strongSelf.mergedTasks[URLIdentifier];
                           if ([mergedTask.identifier isEqual:mergedTaskIdentifier]) {
                               //從合并任務(wù)中,找到自己,并進行移除
                               mergedTask = [strongSelf safelyRemoveMergedTaskWithURLIdentifier:URLIdentifier];
                               if (error) {
                                   for (AFImageDownloaderResponseHandler *handler in mergedTask.responseHandlers) {
                                       if (handler.failureBlock) {
                                           dispatch_async(dispatch_get_main_queue(), ^{
                                               handler.failureBlock(request, (NSHTTPURLResponse*)response, error);
                                           });
                                       }
                                   }
                               } else {
                                   //移除成功后,對圖片進行緩存
                                   if ([strongSelf.imageCache shouldCacheImage:responseObject forRequest:request withAdditionalIdentifier:nil]) {
                                       [strongSelf.imageCache addImage:responseObject forRequest:request withAdditionalIdentifier:nil];
                                   }

                                   for (AFImageDownloaderResponseHandler *handler in mergedTask.responseHandlers) {
                                       if (handler.successBlock) {
                                           dispatch_async(dispatch_get_main_queue(), ^{
                                               handler.successBlock(request, (NSHTTPURLResponse*)response, responseObject);
                                           });
                                       }
                                   }
                                   
                               }
                           }
                           //更新任務(wù)數(shù),并開始下個任務(wù)
                           [strongSelf safelyDecrementActiveTaskCount];
                           [strongSelf safelyStartNextTaskIfNecessary];
                       });
                   }];

    // 4) Store the response handler for use when the request completes
    AFImageDownloaderResponseHandler *handler = [[AFImageDownloaderResponseHandler alloc] initWithUUID:receiptID
                                                                                               success:success
                                                                                               failure:failure];
    
    //把當前任務(wù)添加到合并隊列中
    AFImageDownloaderMergedTask *mergedTask = [[AFImageDownloaderMergedTask alloc]
                                               initWithURLIdentifier:URLIdentifier
                                               identifier:mergedTaskIdentifier
                                               task:createdTask];
    [mergedTask addResponseHandler:handler];
    self.mergedTasks[URLIdentifier] = mergedTask;

    // 5) Either start the request or enqueue it depending on the current active request count
    //如果當前任務(wù)數(shù)沒有超出最大上限,則立即啟動任務(wù)
    if ([self isActiveRequestCountBelowMaximumLimit]) {
        [self startMergedTask:mergedTask];
    } else {
        //按照優(yōu)先級對任務(wù)進行排列
        [self enqueueMergedTask:mergedTask];
    }

    task = mergedTask.task;
});
if (task) {
    return [[AFImageDownloadReceipt alloc] initWithReceiptID:receiptID task:task];
} else {
    return nil;
}
}

核心思想:數(shù)據(jù)共用,各自處理各自的響應(yīng)結(jié)果。

對核心思想細化:

1、找到還未執(zhí)行完的相同任務(wù),如果找到了,就綁定回掉事件,等待任務(wù)執(zhí)行即可。
2、如果緩存策略允許,直接去查圖片,返回成功
3、創(chuàng)建一個下載任務(wù),并添加到等待隊列中
4、如果當前執(zhí)行的任務(wù)數(shù)沒有超過并發(fā)數(shù),則立即執(zhí)行,否則按照優(yōu)先級決定任務(wù)放在隊前還是隊尾
5、執(zhí)行任務(wù)
    5.1、從合并任務(wù)中找到自己,并移除
    5.2、對圖片按照緩存策略進行緩存
    5.3、更新激活的任務(wù)數(shù)并開始下一個任務(wù)

這個核心思想與上一片中的圖片緩存策略合并起來,就是圖片緩存原理的一個雛形了

最后編輯于
?著作權(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ù)。

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