SDWebImage工作流程以及面試題

1.工作流程

1.入口 setImageWithURL:placeholderImage:options: 會(huì)先把placeholderImage 顯示,然后 SDWebImageManager 根據(jù) URL 開始處理圖片。
2.進(jìn)入 SDWebImageManager-downloadWithURL:delegate:options:userInfo:,交給 SDImageCache 從緩存查找圖片是否已經(jīng)下載 3.queryDiskCacheForKey:delegate:userInfo:.
先從內(nèi)存圖片緩存查找是否有圖片,如果內(nèi)存中已經(jīng)有圖片緩存,SDImageCacheDelegate 回調(diào) imageCache:didFindImage:forKey:userInfo: 到 SDWebImageManager。
4、SDWebImageManagerDelegate 回調(diào) webImageManager:didFinishWithImage: 到 UIImageView+WebCache 等前端展示圖片。
5、如果內(nèi)存緩存中沒有,生成 NSInvocationOperation 添加到隊(duì)列開始從硬盤查找圖片是否已經(jīng)緩存。
6、根據(jù) URLKey 在硬盤緩存目錄下嘗試讀取圖片文件。這一步是在 NSOperation 進(jìn)行的操作,所以回主線程進(jìn)行結(jié)果回調(diào) notifyDelegate:。
7、如果上一操作從硬盤讀取到了圖片,將圖片添加到內(nèi)存緩存中(如果空閑內(nèi)存過(guò)小,會(huì)先清空內(nèi)存緩存)。SDImageCacheDelegate 回調(diào) imageCache:didFindImage:forKey:userInfo:。進(jìn)而回調(diào)展示圖片。
8、如果從硬盤緩存目錄讀取不到圖片,說(shuō)明所有緩存都不存在該圖片,需要下載圖片,回調(diào) imageCache:didNotFindImageForKey:userInfo:。
9、共享或重新生成一個(gè)下載器 SDWebImageDownloader 開始下載圖片。
10、圖片下載由 NSURLConnection 來(lái)做,實(shí)現(xiàn)相關(guān) delegate 來(lái)判斷圖片下載中、下載完成和下載失敗。
11、connection:didReceiveData: 中利用 ImageIO 做了按圖片下載進(jìn)度加載效果。connectionDidFinishLoading: 數(shù)據(jù)下載完成后交給 SDWebImageDecoder 做圖片解碼處理。
12、圖片解碼處理在一個(gè) NSOperationQueue 完成,不會(huì)拖慢主線程 UI。如果有需要對(duì)下載的圖片進(jìn)行二次處理,最好也在這里完成,效率會(huì)好很多。
13、在主線程 notifyDelegateOnMainThreadWithInfo: 宣告解碼完成,imageDecoder:didFinishDecodingImage:userInfo: 回調(diào)給 SDWebImageDownloader。imageDownloader:didFinishWithImage: 回調(diào)給 SDWebImageManager 告知圖片下載完成。
14、通知所有的 downloadDelegates 下載完成,回調(diào)給需要的地方展示圖片。將圖片保存到 SDImageCache 中,內(nèi)存緩存和硬盤緩存同時(shí)保存。寫文件到硬盤也在以單獨(dú) NSInvocationOperation 完成,避免拖慢主線程。
15、SDImageCache 在初始化的時(shí)候會(huì)注冊(cè)一些消息通知,在內(nèi)存警告或退到后臺(tái)的時(shí)候清理內(nèi)存圖片緩存,應(yīng)用結(jié)束的時(shí)候清理過(guò)期圖片。
16、SDWI 也提供了 UIButton+WebCache 和 MKAnnotationView+WebCache,方便使用。
17、SDWebImagePrefetcher 可以預(yù)先下載圖片,方便后續(xù)使用。

2.常見面試題目

(1)圖片緩存在那個(gè)目錄下?
緩存的方法在SDImageCache.m里面,圖片默認(rèn)緩存路徑~/Library/Caches/default/com.hackemist.SDWebImageCache.default
(2)圖片下載最大并發(fā)數(shù)和超時(shí)時(shí)間?

#import "SDWebImageDownloader.h"

//下載最大并發(fā)數(shù)
_downloadQueue.maxConcurrentOperationCount = 6;

//下載超時(shí)時(shí)間
 _downloadTimeout = 15.0;

(3)圖片是怎樣命名的?

#import "SDImageCache.h"

//寫入緩存用url做key
NSUInteger cost = SDCacheCostForImage(image);
[self.memCache setObject:image forKey:key cost:cost];

//寫入磁盤需要將url進(jìn)行md5作為圖片的key,防止文件名稱過(guò)長(zhǎng)
- (nullable NSString *)cachedFileNameForKey:(nullable NSString *)key {
    const char *str = key.UTF8String;
    if (str == NULL) {
        str = "";
    }
    unsigned char r[CC_MD5_DIGEST_LENGTH];
    CC_MD5(str, (CC_LONG)strlen(str), r);
    NSURL *keyURL = [NSURL URLWithString:key];
    NSString *ext = keyURL ? keyURL.pathExtension : key.pathExtension;
    NSString *filename = [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%@",
                          r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7], r[8], r[9], r[10],
                          r[11], r[12], r[13], r[14], r[15], ext.length == 0 ? @"" : [NSString stringWithFormat:@".%@", ext]];
    return filename;
}

(4)如何識(shí)別圖片類型?

#import "NSData+ImageContentType.h"

//通過(guò)NSData的第一個(gè)字符判斷圖片類型
+ (SDImageFormat)sd_imageFormatForImageData:(nullable NSData *)data ;

(5)查找到的圖片可以知道圖片來(lái)源嗎?

typedef NS_ENUM(NSInteger, SDImageCacheType) { /**
     * 從網(wǎng)上下載
    */ SDImageCacheTypeNone, /**
     * 從磁盤獲得
     */ SDImageCacheTypeDisk, /**
     * 從內(nèi)存獲得
     */ SDImageCacheTypeMemory
};

(6)所有下載的圖片都將被寫入緩存?磁盤呢?何時(shí)緩存的?

//磁盤不是強(qiáng)制寫入。從枚舉SDWebImageOptions可見
typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) { /**
     *  禁用磁盤緩存
     */ SDWebImageCacheMemoryOnly = 1 << 2,
}

其一是下載成功后、自動(dòng)保存?;蛘唛_發(fā)者通過(guò)代理處理圖片并返回后緩存
其二是當(dāng)緩存中沒有、但是從硬盤中查詢到了圖片,在緩存上進(jìn)行緩存。

(7)磁盤緩存的時(shí)長(zhǎng)?清理操作的時(shí)間點(diǎn)?
默認(rèn)一周清理一次
首先、通過(guò)時(shí)間進(jìn)行清理。(最后修改時(shí)間>一周)
然后、根據(jù)占據(jù)內(nèi)存大小進(jìn)行清理。(如果占據(jù)內(nèi)存大于上限、則按時(shí)間排序、刪除到上限的1/2。)

(8)下載圖片的URL必須是NSURL么?
不是,有容錯(cuò)處理。

(9)讀取緩存以及讀取磁盤的時(shí)候如何保證線程安全?

  • 讀取緩存
    讀取緩存的時(shí)候是在主線程進(jìn)行。由于使用NSCache進(jìn)行存儲(chǔ)、所以不需要擔(dān)心單個(gè)value對(duì)象的線程安全。

  • 讀取磁盤
    磁盤的讀取雖然創(chuàng)建了一個(gè)NSOperation對(duì)象、但據(jù)我所見這個(gè)對(duì)象只是用來(lái)標(biāo)記該操作是否被取消、以及取消之后不再讀取磁盤文件的作用。
    真正的磁盤緩存是在另一個(gè)IO專屬線程中的一個(gè)串行隊(duì)列下進(jìn)行的。
    如果你搜索self.ioQueue還能發(fā)現(xiàn)、不只是讀取磁盤內(nèi)容。
    包括刪除、寫入等所有磁盤內(nèi)容都是在這個(gè)IO線程進(jìn)行、以保證線程安全。
    但計(jì)算大小、獲取文件總數(shù)等操作。則是在主線程進(jìn)行。

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

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