SDWebImage
這個類庫提供一個UIImageView類别以支援加載來自網絡的遠端圖檔。具有緩存管理、異步下載下傳、同一個URL下載下傳次數控制和優化等特征。
SDWebImage 支援異步的圖檔下載下傳+緩存,提供了 UIImageView+WebCacha 的 category,友善使用。SDWebImage加載圖檔的流程:
1. 入口 setImageWithURL:placeholderImage:options: 會先把 placeholderImage顯示,然後 SDWebImageManager 根據 URL 開始處理圖檔。
2. 進入 SDWebImageManager-downloadWithURL:delegate:options:userInfo:,交給 SDImageCache 從緩存查找圖檔是否已經下載下傳 queryDiskCacheForKey:delegate:userInfo:.
3. 先從記憶體圖檔緩存查找是否有圖檔,如果記憶體中已經有圖檔緩存,SDImageCacheDelegate回調 imageCache:didFindImage:forKey:userInfo: 到 SDWebImageManager。
4. SDWebImageManagerDelegate 回調 webImageManager:didFinishWithImage: 到 UIImageView+WebCache等前端展示圖檔。
5. 如果記憶體緩存中沒有,生成 NSInvocationOperation添加到隊列開始從硬碟查找圖檔是否已經緩存。
6. 根據 URLKey在硬碟緩存目錄下嘗試讀取圖檔檔案。這一步是在 NSOperation 進行的操作,是以回主線程進行結果回調 notifyDelegate:。
7. 如果上一操作從硬碟讀取到了圖檔,将圖檔添加到記憶體緩存中(如果空閑記憶體過小,會先清空記憶體緩存)。SDImageCacheDelegate回調 imageCache:didFindImage:forKey:userInfo:。進而回調展示圖檔。
8. 如果從硬碟緩存目錄讀取不到圖檔,說明所有緩存都不存在該圖檔,需要下載下傳圖檔,回調 imageCache:didNotFindImageForKey:userInfo:。
9. 共享或重新生成一個下載下傳器 SDWebImageDownloader 開始下載下傳圖檔。
10. 圖檔下載下傳由 NSURLConnection來做,實作相關 delegate 來判斷圖檔下載下傳中、下載下傳完成和下載下傳失敗。
11. connection:didReceiveData: 中利用 ImageIO做了按圖檔下載下傳進度加載效果。
12. connectionDidFinishLoading: 資料下載下傳完成後交給 SDWebImageDecoder 做圖檔解碼處理。
13. 圖檔解碼處理在一個 NSOperationQueue完成,不會拖慢主線程 UI。如果有需要對下載下傳的圖檔進行二次處理,最好也在這裡完成,效率會好很多。
14. 在主線程 notifyDelegateOnMainThreadWithInfo: 宣告解碼完成,imageDecoder:didFinishDecodingImage:userInfo: 回調給 SDWebImageDownloader。
15. imageDownloader:didFinishWithImage: 回調給 SDWebImageManager告知圖檔下載下傳完成。
16. 通知所有的 downloadDelegates下載下傳完成,回調給需要的地方展示圖檔。
17. 将圖檔儲存到 SDImageCache中,記憶體緩存和硬碟緩存同時儲存。寫檔案到硬碟也在以單獨 NSInvocationOperation 完成,避免拖慢主線程。
18. SDImageCache 在初始化的時候會注冊一些消息通知,在記憶體警告或退到背景的時候清理記憶體圖檔緩存,應用結束的時候清理過期圖檔。
19. SDWI 也提供了 UIButton+WebCache 和 MKAnnotationView+WebCache,友善使用。
20. SDWebImagePrefetcher 可以預先下載下傳圖檔,友善後續使用。
管理類的使用位置:
這個庫最常用到的,是UIImageView的一個Category:UIImageView (WebCache)。
這裡面最常用的一個方法,就是根據URL,加載網絡的圖檔。它的實作如下:
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage*)placeholder
{
SDWebImageManager *manager = [SDWebImageManagersharedManager];
// Remove in progress downloader from queue
[manager cancelForDelegate:self];
self.image = placeholder;
if (url)
{
[manager downloadWithURL:url delegate:self];
}
}
這個方法最大的好處就是,可以不需要改變UI的類,直接添加網絡下載下傳功能。
獨立的異步圖像下載下傳
可能會單獨用到異步圖檔下載下傳,則一定要用downloaderWithURL:delegate:來建立一個SDWebImageDownloader執行個體。
downloader = [SDWebImageDownloader downloaderWithURL:url delegate:self];
這樣SDWebImageDownloaderDelegate協定的方法imageDownloader:didFinishWithImage:被調用時下載下傳會立即開始并完成。
獨立的異步圖像緩存
SDImageCache類提供一個建立空緩存的執行個體,并用方法imageForKey:來尋找目前緩存。
UIImage *myCachedImage = [[SDImageCache sharedImageCache] imageFromKey:myCacheKey];
存儲一個圖像到緩存是使用方法storeImage: forKey:
[[SDImageCache sharedImageCache] storeImage:myImage forKey:myCacheKey];
預設情況下,圖像将被存儲在記憶體緩存和磁盤緩存中。如果僅僅是想記憶體緩存中,要使用storeImage:forKey:toDisk:方法的第三個參數帶一負值
來替代。
SDWebImage庫的作用: 通過對UIImageView的類别擴充來實作異步加載替換圖檔的工作。
主要用到的對象: 1、UIImageView (WebCache)類别,入口封裝,實作讀取圖檔完成後的回調 2、SDWebImageManager,對圖檔進行管理的中轉站,記錄那些圖檔正在讀取。 向下層讀取Cache(調用SDImageCache),或者向網絡讀取對象(調用SDWebImageDownloader)。 實作SDImageCache和SDWebImageDownloader的回調。 3、SDImageCache,根據URL的MD5摘要對圖檔進行存儲和讀取(實作存在記憶體中或者存在硬碟上兩種實作) 實作圖檔和記憶體清理工作。 4、SDWebImageDownloader,根據URL向網絡讀取資料(實作部分讀取和全部讀取後再通知回調兩種方式)
SDImageCache是怎麼做資料管理的?
SDImageCache分兩個部分,一個是記憶體層面的,一個是硬碟層面的。
記憶體層面的相當是個緩存器,以Key-Value的形式存儲圖檔。當記憶體不夠的時候會清除所有緩存圖檔。
用搜尋檔案系統的方式做管理,檔案替換方式是以時間為機關,剔除時間大于一周的圖檔檔案。
當SDWebImageManager向SDImageCache要資源時,先搜尋記憶體層面的資料,如果有直接傳回,沒有的話去通路磁盤,将圖檔從磁盤讀取出來,然後做Decoder,将圖檔對象放到記憶體層面做備份,再傳回調用層。