SDWebImage 4.x版本源碼分析(六)問題總結

問題總結:

1、為什么設置圖片前要取消當前的加載任務?
2、dispatch_group_t 在 UIView+WebCache 里的作用是什么?
3、weak-strong dance的用途?
4、#pragma clang diagnostic push
#pragma clang diagnostic ignored "-W相關命令”
//
#pragma clang diagnostic pop 的作用是什么?

5、如何實現取消下載圖片任務的?

一、為什么設置圖片前要取消當前的加載任務?

如果不取消,那么當tableView滑動的時候,當前cell的imageView會一直去下載圖片,然后優先顯示下載完成的圖片,導致圖片錯亂。

二、dispatch_group_t 在 UIView+WebCache 里的作用是什么?

1.在FLAnimatedImageView(WebCache)中創建了線程組dispatch_group_t,然后通過key為SDWebImageInternalSetImageGroupKey的字典傳入UIView(WebCache)中
— 如果是展示占位圖
2.在UIView(WebCache)中設置占位圖時,首先獲取到是否存在SetImageGroupKey,也就是說是否是FLAnimatedImageView,是就獲取到FLAnimatedImageView(WebCache)中傳來的group,先enter,然后調用setImageBlock中的方法。
3.在setImageBlock中設置self.image,然后leave。
— 通過url加載到圖片后
4.通過url加載到圖片后,拿到group,先enter,然后執行setImageBlock。若此時的圖片是GIF類型的,首先從GIF圖中取出第一張,設為靜態海報圖像,避免閃爍。其次在全局隊列中異步創建FLAnimatedImage,然后在主線程中設置self.animatedImage,并leave group。
5.notify中的block,也就是當group中的所有任務都完成后,調用下[self setNeedsLayout]; - setNeedsLayout 的作用是標記,標記為需要重新布局,異步調用layoutIfNeeds 刷新布局,不利己刷新,但layoutSubviews一定會被調用。

三、weak-strong dance的用途

通過__weak來避免循環引用,weakSelf是附有__weak修飾符的變量,它并不會持有對象,一旦它指向的對象被廢棄了,它將自動被賦值為nil。
在多線程情況下,可能weakSelf指向的對象會在 Block 執行前被廢棄。
通過__strong來持有weakSelf指向的對象,保證在執行 Block 期間該對象不會被廢棄。

四、

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-W相關命令”
//
#pragma clang diagnostic pop 的作用是什么?

忽略clang編譯器警告,如下面的代碼如果不寫會提示 Undeclared selector ‘dynamicSelector’,

//#pragma clang diagnostic push
//#pragma clang diagnostic ignored "-Wundeclared-selector"
    [self performSelector:@selector(dynamicSelector) withObject:nil];
//#pragma clang diagnostic pop

五、如何實現取消下載圖片任務的?

1.在UIView(WebCache)里,首先就調用了取消當前的加載任務。

- (void)sd_cancelImageLoadOperationWithKey:(nullable NSString *)key
{
    // 從隊列中取消進度下載
    SDOperationsDictionary *operationDictionary = [self sd_operationDictionary];
    id<SDWebImageOperation> operation;
    @synchronized (self) {
        // 根據key取出當前的操作 (這里取出的operation是實現了SDWebImageOperation協議的 SDWebImageCombinedOperation)
        operation = [operationDictionary objectForKey:key];
    }
    if (operation) {
        //檢查是否實現了SDWebImageOperation協議的方法
        if ([operation conformsToProtocol:@protocol(SDWebImageOperation)]){
            [operation cancel];
        }
        @synchronized (self) {
            [operationDictionary removeObjectForKey:key];
        }
    }
}

這里做了兩件事,
1.從operationDictionary中取出operation(實際上就是SDWebImageCombinedOperation),
2.判斷operation是否實現了SDWebImageOperation協議(SDWebImageCombinedOperation實現了這個協議),調用取消方法,并從operationDictionary中移除key。

2.SDWebImageCombinedOperation里實現了cancel

@implementation SDWebImageCombinedOperation
- (void)cancel {
    @synchronized(self) {
        self.cancelled = YES;
        if (self.cacheOperation) {
            [self.cacheOperation cancel                                           ];
            self.cacheOperation = nil;
        }
        if (self.downloadToken) {
            [self.manager.imageDownloader cancel:self.downloadToken];
        }
        [self.manager safelyRemoveOperationFromRunning:self];
    }
}

<1.cancel掉self.cacheOperation <NSOperation>
<2.manager的imageDownloader cancel掉 self.downloadToken
<3.manager.runningOperation中刪掉self

其中第<2點,調用的SDWebImageDownloader 的-cancel:方法

3.SDWebImageDownloader的-cancel:方法

- (void)cancel:(nullable SDWebImageDownloadToken *)token {
    NSURL *url = token.url;
    if (!url) {
        return;
    }
    LOCK(self.operationsLock);
    SDWebImageDownloaderOperation *operation = [self.URLOperations objectForKey:url];
    if (operation) {
        BOOL canceled = [operation cancel:token.downloadOperationCancelToken];
        if (canceled) {
            [self.URLOperations removeObjectForKey:url];
        }
    }
    UNLOCK(self.operationsLock);
}

<<1.從manager的URLOperations中找到 SDWebImageDownloaderOperation < SDWebImageDownloaderOperationInterface,SDWebImageOperation>
<<2.operation 調用cancel token.downloadOperationCancelToken (這個token.downloadOperationCancelToken 就是回調的字典)
<<3.如果需要取消,從URLOperation中刪掉url

其中<<2調用的是SDWebImageDownloaderOperation的-cancel:方法

4.SDWebImageDownloaderOperation 刪除保存回調的字典

- (BOOL)cancel:(nullable id)token {
    BOOL shouldCancel = NO;
    //同步 阻塞當前隊列和當前線程(用的信號量)
    LOCK(self.callbacksLock);
    //刪除數組中回調塊數組中的token對象,token是key為string,value是block的字典
    //removeObjectIdenticalTo 刪掉地址該token的地址,而不是值。
    [self.callbackBlocks removeObjectIdenticalTo:token];
    //判斷數組是否為0.則取消下載任務
    if (self.callbackBlocks.count == 0) {
        shouldCancel = YES;
    }
    UNLOCK(self.callbacksLock);
    if (shouldCancel) {
        [self cancel];
    }
    return shouldCancel;
}

<<<1.從callbackBlocks中刪掉token(刪掉回調的字典)
<<<2.如果Blocks數組為0,取消下載任務,shouldCancel = YES;
<<<3.如果Blocks數組為0,調用 [self cancel];
<<<4.返回shouldCancel

對于<<<3中的[self cancel]; 實際上調用的是SDWebImageDownloaderOperation的cancel方法

5.SDWebImageDownloaderOperation 取消下載任務

- (void)cancel {
    @synchronized (self) {
        [self cancelInternal];
    }
}

- (void)cancelInternal {
    if (self.isFinished) return;
    [super cancel];
    //如果下載圖片的任務仍在 則立即取消cancel,并且發送結束下載的通知
    if (self.dataTask) {
        [self.dataTask cancel];
        __weak typeof(self) weakSelf = self;
        dispatch_async(dispatch_get_main_queue(), ^{
            [[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:weakSelf];
        });
        // As we cancelled the task, its callback won't be called and thus won't
        // maintain the isFinished and isExecuting flags.
        if (self.isExecuting) self.executing = NO;
        if (!self.isFinished) self.finished = YES;
    }
    [self reset];
}

<<<<1.super cancel
<<<<2.如果還有任務,NSURLSessionTask cancel
<<<<3.通知結束下載

這樣就完成了取消下載任務。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,885評論 6 541
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,312評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,993評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,667評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,410評論 6 411
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,778評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,775評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,955評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,521評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,266評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,468評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,998評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,696評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,095評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,385評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,193評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,431評論 2 378

推薦閱讀更多精彩內容