IOS網絡圖片庫
移動端架構中圖片庫是非常重要的一環,其實圖片庫也可以理解為網絡庫的一種特殊使用模式,為了滿足需要,圖片庫至少要滿足以下特點:
- 提供一個加載入口,通常以UIImageView的類別方法setImageWithURL:...開始
- 支持異步網絡加載圖片
- 支持內存緩存和文件緩存
- 確保同一張圖片不會被重復下載
- 主流圖片格式的解碼 </ul>
- </li>
- </li>
-
EGOImageLoading 已經年久失修
</li> </ul>1. Load入口
關于Load入口方式,一般有兩種方式,SDWebImage 中的Category 方式,和EGOImageLoading中的繼承模式。不過EGOImageLoading已經年久失修,早就不流行了,SDWebImage的方式更流行,Category的方式也顯得更好,因為不需要對業務代碼做太多侵入。所以Extension的方式貌似無可爭議。
2. 圖片的下載
首先你要設計一個全局的隊列來執行下載任務,因為我們要保證下載任務不重復,那么就需要一個任務管理器來統一調度下載任務,比如有2個UIImageView同時加載同一張圖片,那么就只執行一次下載,下載完成回調給2個View就行了。
回調的方式SDWebImage采用block的方式,EGOImageLoading采用了Notification的方式, 因為可能存在多個回調,所以不太適合用delegate的方式進行回調,不過如果非要想用也可以,可以創建一個weak引用的CFArrayRef或者用NSHashTable來把保存 delegate 指針。
SDWebImageDownloaderOperation作為 SDWebImage 的網絡Operation的設計,如果有同學研究過源碼可以發現,SDWebImageDownloaderOperation里面維持了線程的存在(通過啟用RunLoop), 這個設計貌似和我上篇文章IOS應用架構思考一(網絡層) 中說的不太一致。SDWebImage 之所以這樣設計是有意義的,就是圖片數據解碼的工作,特別是當Option設置為SDWebImageDownloaderProgressiveDownload時,每接收到一點data都要解碼出一個圖片, 這些解碼的工作就可以繼續在這個線程里面執行了,當然我覺得也不一定非要如此設計,dispatch_quque本來對于線程的管理就有一套了,只要保證圖片解碼在后臺執行就行了,比如AFNetworking中也做到了圖片解碼放在后臺。這一點的設計其實沒有AFNetworking好
3. 緩存
3.1 緩存方式選擇
說到緩存,我們知道在IOS5之后,NSURLCache 也有diskCache了,是不是我們不需要自己實現cache機制了,直接使用NSURLCache就好了呢?分析這個必要性,我們首先要思考NSURLCache中保存的是什么,NSURLCache中保存的是Http協議返回的rawData, 沒有經過解壓和解碼的過程,如果直接使用NSURLCache, 那么每次讀緩存的時候就還需要把rawData解碼為我們需要的UIImage,這肯定會帶來額外的CPU開銷。那如果我們自己來做緩存,我們可以將解碼后的數據保存到disk,就可以減少我們讀緩存的時間了。這一點也是我覺得SDWebImage唯一比AFNetworking好的一個亮點了,其他的AFNetworking也都做到了,(AFNetworking直接使用NSURLCache做diskCache, 在后臺線程解碼image)
3.2 內存緩存
關于緩存,我們還需要設計內存緩存,diskCache 在讀取的時候還是要消耗I/O的時間,可能帶來對FPS的影響和電量的消耗,那么我們設計內存緩存在一定程度上可以緩解這個問題,對于頻繁使用的圖片,效果會更好。PS: 內存緩存需要做好內存控制,不能讓其過多的占用內存,比如內存警告時要清空。 NSURLCache 雖然也有內存緩存,但是不太可控,所以內存緩存還是自己實現比較合適。
3.3 緩存時間
緩存時間的設定其實比較重要,其實有時候緩存時間的設置,使用NSURLCache的話,緩存時間可以是由圖片服務器來決定的,客戶端不用太操心什么,這個是用NSURLCache的好處,那么如果我們自己實現的緩存方式呢,SDWebImage里面是可以統一設置緩存的時間,默認是一周的時間,其實這個設定我是覺得不太合理的,因為不同的業務場景很可能會要求不同的緩存時間設定,怎么能夠大一統的設置了事,不過好在現在的一般應用場景沒有對緩存時間硬性的要求,所以用起來也沒什么問題。
話說我以前在蘇寧易購的時候,就對EGOImageLoading做過大修改,添加了很多SDWebImage的優點特性,關于緩存時間也做了個性化設定。但其實NSURLCache 的方式才是決定緩存壽命的最好的方式。
4. 圖片解碼
作為一個圖片庫,支持主流圖片格式的解碼那是必須的,像png, jpg, gif這些肯定是要支持的,現在很火的webp也是需要考慮支持的,webp對網絡流量和速度的提升意義是很大的。Google已經開源了libwebp, 而且SDWebImage現在也已經支持了WebP格式的解碼可以參考SDWebImage的使用將WebP的功能集成進去。
5. 其他
5.1 漸進加載
圖片漸進加載可能也是產品體驗上錦上添花的一個點了,圖片漸進加載要取決于JPEG圖片的保存格式了,主要有兩種Baseline JPEG和Progressive JPEG, 在漸進加載的過程中Baseline JPEG就會一行一行的展示,而Progressive JPEG就可以從模糊到清晰的方式,毫無疑問Progressive JPEG的方式是可以提升用戶體驗的方式,圖片的格式正確后,SDWebImage中只需要將option設置為SDWebImageDownloaderProgressiveDownload時,就可以實現圖片漸進顯示了,其實也就是使用了ImageIO 來解析:progressive-images-download-imageio
5.2 圖片裁剪
有時候可能會有一些圖片裁剪的需求,比如說placeholder隨著view大小自適應,或者一張源圖片可能會裁剪為不同尺寸來展示,那么這個時候可能會做一些裁剪的操作,裁剪操作可能需要做到2點,不要在主線程做,不要重復裁剪相同尺寸。
5.3 FastImageCache
FastImageCache 是Path開源的關于圖片緩存的庫,它不是一個網絡庫,只是一個圖片緩存庫,實現了disk內存映射對FPS提升很有幫助,一般應用不太需要使用,但是對于圖片類應用絕對是優化利器,iOS圖片加載速度極限優化—FastImageCache解析 這篇文章對于FastImageCache的講解非常詳細。
來自:http://blog.cnbluebox.com/blog/2015/07/10/architecture-ios-2/
著名的優秀關于圖片加載的庫有: