超讚的 SDWebImage 框架( 和AF提供的圖片快取比較 )
SDWebImage 是一個超級牛逼的開源框架。我們 如果只滿足於公開的api來使用它,那麼你可能不會對這個開源框架的作者佩服,也就不知道這個框架是迄今為止,在ios中來說,快取時做的最好的一個(沒有之一)。 記得以前早些時候去百度面試的時候,那時的技術大牛問我的問題,就是:你看過SDWebImage 框架的原始碼嗎?好了,廢話不多說,開始說說 SDWebImage 這個框架吧。
說到這個框架的快取,那麼就不能不提到計算機組成原理,(什麼?計算機?關手機毛事啊!)哈哈,手機中的ARM板其實就是參照了計算機中的設計思想。如果ARM板你也沒聽過,那麼我就只能說,你對硬體知識瞭解的太少。你在開發ios的過程中,肯定遇到過 錯誤問題 關於 arm_v7 或者arm_v7s 。這裡就是arm板。 好了,如果你想成為一個嵌入式開發的人才,那麼推薦你去學一下《arm體系架構》一共有2本書。回到正題,SDWebImage 的圖片快取是了不起,所以,從圖片快取來說,計算機是如何 實現一個圖片展示的?如果圖片存在在本地磁碟中,第一步:先從磁碟取出圖片放入到主存中(也就是我們說的記憶體),第二步:cache快取記憶體,現在的計算機設計模式,已經設計一個轉接空間,連線cpu 和 主存 。圖片第一次放入cpu進行運算渲染的時候,會把資料放到cache快取記憶體中,而快取記憶體裡採用管理的演算法也有很多種,這個在作業系統中可以查詢到。其中就有演算法--雜湊演算法。arm板展示圖片也就這樣的。如果多次顯示重複的圖片,那麼直接從cache表中是否命中快取,如果命中,直接從cache快取記憶體中展示。好了 基本圖片快取原理大致就是這樣。關於cache的快取記憶體機制,可以參考下《計算機組成原理》,它的管理 又作業系統和硬體設計已經很好的幫助我們管理。所以軟體程式猿不用去理會它。
AFNetworking整合的UIImageView+AFNetworking.h,對於圖片的快取實際應用的是NSURLCache自帶的cache機制。而NSURLCache每次都要把快取的raw data 再轉化為UIImage,就帶來了資料處理和記憶體方面的更多操作。
SDWebImage 和AFNetworking 的比較:
Since iOS 5.0, NSURLCache handles disk caching, what is the advantage of SDWebImage over plain NSURLRequest?
iOS NSURLCache does memory and disk caching (since iOS 5) of raw HTTP responses. Each time the cache is hit, your app will have to transform the raw cached data into an UIImage. This involves extensive operations like data parsing (HTTP data are encoded), memory copy etc.
On the other side, SDWebImage caches the UIImage representation in memory and store the original compressed (but decoded) image file on disk. UIImage are stored as-is in memory using NSCache, so no copy is involved, and memory is freed as soon as your app or the system needs it.
Additionally, image decompression that normally happens in the main thread the first time you use UIImage in an UIImageView is forced in a background thread by SDWebImageDecoder.
Last but not least, SDWebImage will completely bypass the complex and often misconfigured HTTP cache control negotiation. This greatly accelerates cache lookup.
Since AFNetworking provides similar functionality for UIImageView, is SDWebImage still useful?
Arguably not. AFNetworking takes advantage of Foundation URL Loading System caching using NSURLCache
, as well as
a configurable in-memory cache for UIImageView
and UIButton
,
which uses NSCache
by default. Caching behavior can be further specified in the caching policy of a corresponding NSURLRequest
.
Other SDWebImage features, like background decompression of image data is also provided by AFNetworking.
If you're already using AFNetworking and just want an easy async image loading category, the built-in UIKit extensions will probably fit your needs.
時間不足,暫時分享別人總結的:
SDWebImage提供瞭如下三個category來進行快取。
以最為常用的UIImageView為例:
- UIImageView+WebCache:
setImageWithURL:placeholderImage:options:
先顯示 placeholderImage ,同時由SDWebImageManager 根據 URL 來在本地查詢圖片。 - SDWebImageManager:
downloadWithURL:delegate:options:userInfo:
SDWebImageManager是將UIImageView+WebCache同SDImageCache連結起來的類, SDImageCache:queryDiskCacheForKey:delegate:userInfo:
用來從快取根據CacheKey查詢圖片是否已經在快取中 - 如果記憶體中已經有圖片快取, SDWebImageManager會回撥SDImageCacheDelegate :
imageCache:didFindImage:forKey:userInfo:
- 而 UIImageView+WebCache 則回撥SDWebImageManagerDelegate:
webImageManager:didFinishWithImage:
來顯示圖片。 - 如果記憶體中沒有圖片快取,那麼生成 NSInvocationOperation 新增到佇列,從硬碟查詢圖片是否已被下載快取。
- 根據 URLKey 在硬碟快取目錄下嘗試讀取圖片檔案。這一步是在 NSOperation 進行的操作,所以回主執行緒進行結果回撥
notifyDelegate:
。 - 如果上一操作從硬碟讀取到了圖片,將圖片新增到記憶體快取中(如果空閒記憶體過小,會先清空記憶體快取)。SDImageCacheDelegate 回撥
imageCache:didFindImage:forKey:userInfo:
。進而回調展示圖片。 - 如果從硬碟快取目錄讀取不到圖片,說明所有快取都不存在該圖片,需要下載圖片,回撥
imageCache:didNotFindImageForKey:userInfo:
。 - 共享或重新生成一個下載器
SDWebImageDownloader
開始下載圖片。 - 圖片下載由 NSURLConnection 來做,實現相關 delegate 來判斷圖片下載中、下載完成和下載失敗。
connection:didReceiveData:
中利用 ImageIO 做了按圖片下載進度載入效果。connectionDidFinishLoading:
資料下載完成後交給SDWebImageDecoder
做圖片解碼處理。- 圖片解碼處理在一個 NSOperationQueue 完成,不會拖慢主執行緒 UI。如果有需要對下載的圖片進行二次處理,最好也在這裡完成,效率會好很多。
- 在主執行緒
notifyDelegateOnMainThreadWithInfo:
宣告解碼完成,imageDecoder:didFinishDecodingImage:userInfo:
回撥給 SDWebImageDownloader。 imageDownloader:didFinishWithImage:
回撥給 SDWebImageManager 告知圖片下載完成。- 通知所有的 downloadDelegates 下載完成,回撥給需要的地方展示圖片。
- 將圖片儲存到 SDImageCache 中,記憶體快取和硬碟快取同時儲存。
- 寫檔案到硬碟在單獨 NSInvocationOperation 中完成,避免拖慢主執行緒。
- 如果是在iOS上執行,SDImageCache 在初始化的時候會註冊notification 到 UIApplicationDidReceiveMemoryWarningNotification 以及 UIApplicationWillTerminateNotification,在記憶體警告的時候清理記憶體圖片快取,應用結束的時候清理過期圖片。
SDWebImagePrefetcher
可以預先下載圖片,方便後續使用。