胡說八道 - 3 SDWebImage 見語

SDWebImage 簡要介紹

SDWebImage 是一款性能卓越、流行度高的網(wǎng)絡(luò)圖片下載框架。對 SDWebImage 框架代碼解讀的文章數(shù)不勝數(shù),這里只胡說八道框架的設(shè)計思想袱箱。
[注]:推薦南峰子的博客 《源碼解析:SDWebImage 實現(xiàn)分析》
《計算機組成與設(shè)計:硬件/軟件接口》 CPU 和 存儲管理講的很好。第三版义矛、第四版均可发笔。

框架設(shè)計思想剖析

SDWebImage 加載圖片的流程

流程參考這里 《那些著名或非著名的 iOS 面試題 - 前編》

1.入口 setImageWithURL:placeholderImage:options: 會先把 placeholderImage 顯示,然后 SDWebImageManager 根據(jù) URL 開始處理圖片凉翻。

2.進入 SDWebImageManager-downloadWithURL:delegate:options:userInfo:了讨,交給 SDImageCache 從緩存查找圖片是否已經(jīng)下載 queryDiskCacheForKey:delegate:userInfo:.

3.先從內(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 添加到隊列開始從硬盤查找圖片是否已經(jīng)緩存残炮。

6.根據(jù) URLKey 在硬盤緩存目錄下嘗試讀取圖片文件。這一步是在 NSOperation 進行的操作缩滨,所以回主線程進行結(jié)果回調(diào) notifyDelegate:势就。

7.如果上一操作從硬盤讀取到了圖片,將圖片添加到內(nèi)存緩存中(如果空閑內(nèi)存過小脉漏,會先清空內(nèi)存緩存)苞冯。SDImageCacheDelegate 回調(diào) imageCache:didFindImage:forKey:userInfo:。進而回調(diào)展示圖片侧巨。

8.如果從硬盤緩存目錄讀取不到圖片舅锄,說明所有緩存都不存在該圖片,需要下載圖片司忱,回調(diào) imageCache:didNotFindImageForKey:userInfo:皇忿。

9.共享或重新生成一個下載器 SDWebImageDownloader 開始下載圖片畴蹭。

10.圖片下載由 NSURLConnection 來做,實現(xiàn)相關(guān) delegate 來判斷圖片下載中鳍烁、下載完成和下載失敗叨襟。

11.connection:didReceiveData: 中利用 ImageIO 做了按圖片下載進度加載效果。

12.connectionDidFinishLoading: 數(shù)據(jù)下載完成后交給 SDWebImageDecoder 做圖片解碼處理幔荒。

13.圖片解碼處理在一個 NSOperationQueue 完成糊闽,不會拖慢主線程 UI。如果有需要對下載的圖片進行二次處理爹梁,最好也在這里完成右犹,效率會好很多。

14.在主線程 notifyDelegateOnMainThreadWithInfo: 宣告解碼完成姚垃,imageDecoder:didFinishDecodingImage:userInfo: 回調(diào)給 SDWebImageDownloader念链。

15.imageDownloader:didFinishWithImage: 回調(diào)給 SDWebImageManager 告知圖片下載完成。

16.通知所有的 downloadDelegates 下載完成莉炉,回調(diào)給需要的地方展示圖片钓账。

17.將圖片保存到 SDImageCache 中,內(nèi)存緩存和硬盤緩存同時保存絮宁。寫文件到硬盤也在以單獨 NSInvocationOperation 完成梆暮,避免拖慢主線程。

18.SDImageCache 在初始化的時候會注冊一些消息通知绍昂,在內(nèi)存警告或退到后臺的時候清理內(nèi)存圖片緩存啦粹,應(yīng)用結(jié)束的時候清理過期圖片。

總結(jié)

總體設(shè)計思路

  1. 內(nèi)存中維護一個圖片緩存作為一級緩存窘游,輔存中維護一個圖片緩存作為二級緩存唠椭。同時共享的下載器緩存下載任務(wù),減少下載時的資源消耗忍饰。進行文件查找贪嫂、文件下載、圖片解碼艾蓝、文件讀寫操作等都使用后臺線程完成力崇,減少對程序性能的影響。

設(shè)計經(jīng)驗

  1. 設(shè)計模式
    Observer赢织、Delegate 亮靴、Singleton 的混合使用,使各功能組件的配合更加高效于置。這些簡單的設(shè)計模式也沒有那么不堪茧吊,關(guān)鍵是不亂套、不濫用。
  2. 性能優(yōu)化
    1. 功能明確分開
      文件查找搓侄、文件下載瞄桨、文件讀寫、圖片解碼等操作都交由對應(yīng)的功能組件完成讶踪,代碼清晰讲婚,結(jié)構(gòu)明確。
  3. 多線程的使用
    處理必要的 UI 數(shù)據(jù)交換俊柔,其他的操作都盡可能的在后臺線程完成,減少對主線程的影響活合。
  4. 架構(gòu)設(shè)計
  5. 多級緩存的靈活使用
    內(nèi)存中緩存圖片作為一級緩存雏婶,輔存中緩存圖片作為二級緩存;還對可能出現(xiàn)資源損耗的下載操作實現(xiàn)一次緩存白指。
    [注] 緩存的使用不是越多多好留晚,請慎重選擇使用。
  6. 功能組件的設(shè)置
    將功能組件分開告嘲,各司其職错维。做到代碼結(jié)構(gòu)清晰,功能有條不紊橄唬。(這里將‘文件下載’赋焕、‘文件IO’的操作稱為功能組件并不合適,只是為了便于理解思路仰楚。)

題外話

  1. 多線程
    什么時候應(yīng)該使用多線程隆判?
  2. 完成線程或者任務(wù)間的同步操作
  3. 減少多主線程的性能影響,提高反應(yīng)速度僧界。使用后臺線程侨嘀。

多線程中應(yīng)該考慮什么?

  1. 添加什么方式的任務(wù)到隊列中捂襟?同步方式還是異步方式咬腕?(同步任務(wù)和異步任務(wù)的區(qū)別是什么?為是否阻塞當前線程葬荷,以同步方式添加任務(wù)到隊列中會阻塞當前線程)

  2. 怎么去執(zhí)行線程涨共?串行還是并行?

3. 線程安全的闯狱?
典型的解決線程安全問題的方法:使用線程鎖實現(xiàn)煞赢。對應(yīng)各有優(yōu)缺點。
這里推薦解決線程安全問題幾篇文章:1.Objc 線程安全類的設(shè)計系列文章 2.多線程開發(fā)之線程安全 3.簡書上的 iOS 多線程開發(fā)-線程安全

[注]1. 一個典型的 GCD 死鎖問題
// 1 打印當前線程號
NSLog("之前 - %@", NSThread.currentThread())
// 2 在當前線程中哄孤,向主隊列中添加一個同步任務(wù)
dispatch_sync(dispatch_get_main_queue(), { () -> Void in
NSLog("sync - %@", NSThread.currentThread())
})
// 3 沒有切換線程照筑,在主線程中打印
NSLog("之后 - %@", NSThread.currentThread())
結(jié)果:只能輸出:之前 - XX
步驟分解:
1 在主線程中先獲取主線程隊列,以同步的方式添加一個任務(wù)到主線程隊列中。
2 主線程隊列中的任務(wù)會被取出串行執(zhí)行凝危,同時因為是同步方式波俄,所以會阻塞當前主隊列線程
3 主線程被阻塞,不能被執(zhí)行
[注] 2. 實現(xiàn)線程間數(shù)據(jù)同步或者通信
兩種實現(xiàn)方式:GCD 實現(xiàn) 和 NSOperation 實現(xiàn)蛾默。

  1. 緩存
    強烈推薦閱讀《計算機組成與設(shè)計:硬件與軟件接口》懦铺。
  2. 架構(gòu)
    好的架構(gòu)是一步一步進化出來的,而不是一次就完成所有架構(gòu)的支鸡。但是不可否認冬念,編寫代碼時,應(yīng)該遵循良好的編碼規(guī)范和設(shè)計方法牧挣。

小技巧

  1. 不同網(wǎng)絡(luò)狀態(tài)下的圖片加載處理
    場景:3/4G 和 WiFi 環(huán)境下的高清圖片和普通質(zhì)量圖片的顯示問題
    SDWebImage 會默認加載緩存中的高清圖片急前,為了節(jié)省用戶的流量,應(yīng)該對網(wǎng)絡(luò)狀態(tài)進行判斷瀑构,控制加載不同質(zhì)量的圖片裆针。但是這還沒有完,有些用戶默認設(shè)置在 3/4 G 網(wǎng)絡(luò)環(huán)境下加載普通質(zhì)量的圖片(設(shè)置在偏好設(shè)置中)寺晌,該怎么進行省流處理世吨?
    例子:《iOS 開發(fā)-你真的會用 SDWebImage?》
  2. 下載進度展示
    場景:正在下載的 GIF 圖片呻征,被點擊瀏覽大圖耘婚,怎么保證小圖和大圖中顯示的下載進度是一致的?
  3. SDWebImage 設(shè)置圖片圓角怕犁,避免離屏渲染
    場景:設(shè)置圖片圓角边篮,既要快,又不能有離屏渲染奏甫。
    key: 在 ImageView 的分類中戈轿,開啟后臺線程使用 Q2D 進行圖片繪制。

任務(wù)

  1. 自己實現(xiàn)一個文件下載器
    例子:《高效圖片輪播 - 兩個 UIImageView 實現(xiàn)》
  2. 斷點續(xù)傳
    key:使用 HTTP 中的 HEAD 方法阵子,設(shè)置每次下載的文件長度思杯。
    其他的方法請評論告知我,謝謝挠进。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末色乾,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子领突,更是在濱河造成了極大的恐慌暖璧,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件君旦,死亡現(xiàn)場離奇詭異澎办,居然都是意外死亡嘲碱,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進店門局蚀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來麦锯,“玉大人,你說我怎么就攤上這事琅绅》鲂溃” “怎么了?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵千扶,是天一觀的道長料祠。 經(jīng)常有香客問我,道長澎羞,這世上最難降的妖魔是什么术陶? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮煤痕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘接谨。我一直安慰自己摆碉,他們只是感情好,可當我...
    茶點故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布脓豪。 她就那樣靜靜地躺著巷帝,像睡著了一般。 火紅的嫁衣襯著肌膚如雪扫夜。 梳的紋絲不亂的頭發(fā)上楞泼,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天,我揣著相機與錄音笤闯,去河邊找鬼堕阔。 笑死,一個胖子當著我的面吹牛颗味,可吹牛的內(nèi)容都是我干的超陆。 我是一名探鬼主播,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼浦马,長吁一口氣:“原來是場噩夢啊……” “哼时呀!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起晶默,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤谨娜,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后磺陡,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體趴梢,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡漠畜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了垢油。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片盆驹。...
    茶點故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖滩愁,靈堂內(nèi)的尸體忽然破棺而出躯喇,到底是詐尸還是另有隱情,我是刑警寧澤硝枉,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布廉丽,位于F島的核電站,受9級特大地震影響妻味,放射性物質(zhì)發(fā)生泄漏正压。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一责球、第九天 我趴在偏房一處隱蔽的房頂上張望焦履。 院中可真熱鬧,春花似錦雏逾、人聲如沸嘉裤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽屑宠。三九已至,卻和暖如春仇让,著一層夾襖步出監(jiān)牢的瞬間典奉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工丧叽, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留卫玖,地道東北人。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓踊淳,卻偏偏與公主長得像骇笔,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子嚣崭,可洞房花燭夜當晚...
    茶點故事閱讀 43,452評論 2 348

推薦閱讀更多精彩內(nèi)容