SDWebImage淺析

最近幾個項目在使用到圖片的時候都采取異步加載的情況,然而原生的ImageView的相關(guān)方式是同步執(zhí)行的,如果圖片太大或者網(wǎng)絡(luò)條件不佳,那么就會造成主界面卡死。所以我們最后才用的是SDWebImage這個庫。像往常一樣,我們還是來簡單分析一下SD都做了哪些事情。

SD的源碼大致可分為兩部分,功能類和Category,功能類包含如下文件,我們來一個個地分析。

Paste_Image.png

SDImageCache負責(zé)管理圖片的緩存,包括使用NSCache實現(xiàn)內(nèi)存緩存以及使用NSFileManger實現(xiàn)磁盤緩存,對外提供了配置參數(shù)、存儲/刪除/查詢圖片緩存的方法。

SDWebImageCompat負責(zé)對Image進行縮放處理,以兼容2x/3x。這里有一個細節(jié)需要注意:

inline UIImage *SDScaledImageForKey(NSString *key, UIImage *image)

方式用了inline進行了修飾,inline的好處是對于需要頻繁調(diào)用的方法,可以提高運行效率。具體可參見這里。于是我按照博客上的例子試了試,看了一下匯編的代碼,發(fā)現(xiàn)并沒有call與不call的區(qū)別,都是"bl _add",于是又Google了一下,發(fā)現(xiàn)了這個
這里面提到即使使用inline,編譯器也不一定就這么做,最終決定權(quán)在編譯器,代碼里的聲明只是建議。而且現(xiàn)在CPU速度很快,遞歸棧的速度也基本忽略不計了,對效率的影響并不大。

SDWebImageDecoder負責(zé)圖片的解碼。這里有個點,即通過 imageNamed 創(chuàng)建 UIImage 時,系統(tǒng)實際上只是把這個文件名放到 UIImage 里返回,并沒有進行實際的文件讀取和解碼。當(dāng) UIImage 第一次顯示到屏幕上時,其內(nèi)部的解碼方法才會被調(diào)用。這樣帶來的結(jié)果就是對于特別大的圖,在顯示的時候會出現(xiàn)延遲。

SDWebImageDownloader負責(zé)圖片的下載。包括設(shè)置是否解碼、并發(fā)量、使用NSOperationQueue管理請求等。

SDWebImageDownloaderOperation繼承NSOperation,處理業(yè)務(wù)層傳遞來的回調(diào)事件。

SDWebImageManager負責(zé)對業(yè)務(wù)層提供下載圖片、緩存圖片、檢查圖片是否存在等方法。

SDWebImagePrefetcher可以預(yù)下載圖片,方便以后使用,個人理解就是比直接用Manager預(yù)加載更方便一點,因為作者已經(jīng)把相關(guān)的代碼封裝好了。

下面以最常用的[UIImageView sd_setImageWithURL]方法為例,分析一下SD的大致流程:
1)取消之前的請求;

[self sd_cancelCurrentImageLoad];

2)設(shè)置占位圖;

if (!(options & SDWebImageDelayPlaceholder)) {
        dispatch_main_async_safe(^{
            self.image = placeholder;
        });
    }

3)通過SDWebImageManager處理下載邏輯,并將此次加載圖片的請求保存,以便cancel;

id <SDWebImageOperation> operation = [SDWebImageManager.sharedManager downloadImageWithURL:url options:options progress:progressBlock completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
            //......
            });
        }];
        [self sd_setImageLoadOperation:operation forKey:@"UIImageViewImageLoad"];

4)檢查image是否在內(nèi)存中存在;

UIImage *image = [self imageFromMemoryCacheForKey:key];
    if (image) {
        doneBlock(image, SDImageCacheTypeMemory);
        return nil;
    }

5)檢查image在磁盤中是否存在;

NSOperation *operation = [NSOperation new];
    dispatch_async(self.ioQueue, ^{
        if (operation.isCancelled) {
            return;
        }

        @autoreleasepool {
            UIImage *diskImage = [self diskImageForKey:key];
            if (diskImage && self.shouldCacheImagesInMemory) {
                NSUInteger cost = SDCacheCostForImage(diskImage);
                [self.memCache setObject:diskImage forKey:key cost:cost];
            }

            dispatch_async(dispatch_get_main_queue(), ^{
                doneBlock(diskImage, SDImageCacheTypeDisk);
            });
        }
    });

6)通過imageDownloader下載圖片;

id <SDWebImageOperation> subOperation = [self.imageDownloader downloadImageWithURL:url options:downloaderOptions progress:progressBlock completed:^(UIImage *downloadedImage, NSData *data, NSError *error, BOOL finished)

7)在內(nèi)存和磁盤中保存image;

[self.imageCache storeImage:transformedImage recalculateFromImage:imageWasTransformed imageData:(imageWasTransformed ? nil : data) forKey:key toDisk:cacheOnDisk];

8)處理業(yè)務(wù)層的回調(diào);

completedBlock(transformedImage, nil, SDImageCacheTypeNone, finished, url);
最后編輯于
?著作權(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)容