多圖下載綜合案例
- tableView- cell- cell上面有圖標(biāo)、標(biāo)題、子標(biāo)題
- 圖片來源:網(wǎng)絡(luò)下載圖片app.plist
- 耗時(shí)操作,需要在子線程中執(zhí)行
搭建界面
- storyboard:tableViewController
- is initial
- class:ViewController
- 描述cell
- style:subtitle
- indentifier
- ViewController:UITableViewCotroller
數(shù)據(jù)展示
-
提供數(shù)據(jù)源
- 定義數(shù)組屬性
- 懶加載
- 加載plist文件
- 字典數(shù)組轉(zhuǎn)成模型數(shù)組
- 創(chuàng)建可變數(shù)組
- 遍歷字典數(shù)組
- 把每一個(gè)字典轉(zhuǎn)成模型
-
創(chuàng)建模型
- 模型屬性name/icon/download
- 提供一個(gè)類方法:appWithDict:
-
實(shí)現(xiàn)數(shù)據(jù)源方法
- 多少組
- 每組有多少行
- 定義cell視圖
- 創(chuàng)建cell
- 設(shè)置cell數(shù)據(jù):標(biāo)題,子標(biāo)題,圖片
- 圖片下載
- URL
- 二進(jìn)制數(shù)據(jù)下載到本地
- 轉(zhuǎn)換格式
- 圖片下載
- 返回cell
修改配置文件:ATS特性
緩存處理
-
問題1:UI卡頓
- 原因:把下載圖片的耗時(shí)操作都放在主線程執(zhí)行
- 解決:開啟子線程來下載圖片
-
問題2:拖動(dòng)圖片的時(shí)候,圖片重復(fù)下載
- 耗流量
- 原因:滾動(dòng)的時(shí)候會(huì)重新調(diào)用cellForRowAtIndextPath來顯示圖片
- 解決:把下載的圖片保存起來,下載圖片之前,先檢查本地有沒有,如果有直接設(shè)置圖片,就不重復(fù)下載了
使用字典:一一對應(yīng)
-
定義一個(gè)可變字典屬性
- 懶加載,判斷有沒有做初始化處理,做初始化處理
思路:當(dāng)把圖片下載圖片完成之后,需要把該圖片保存到內(nèi)存緩存當(dāng)中;在需要顯示圖片的時(shí)候,先檢查本地的緩存中是否已經(jīng)下載了該圖片;如果緩存中有該圖片,直接設(shè)置就可以了,如果緩存中沒有該圖片,此時(shí)需要去下載圖片
-
把圖片保存到內(nèi)存緩存
- setObject:image forKey:name/dowload/icon
- 建議用url作為key值
- setObject:image forKey:name/dowload/icon
嘗試去字典里去取值,用key值去取
-
[self.images objectForKey:]
- 如果有,設(shè)置圖片
- 如果沒有,下載圖片
-
問題:保存到內(nèi)存里了,是用屬性接收圖片的,退出程序后,重新運(yùn)行程序,圖片還是會(huì)重新下載
- 怎么做到永遠(yuǎn)只下載一次
- 如何改善緩存結(jié)構(gòu),改成二級緩存結(jié)構(gòu)(沙盒緩存)
二級緩存結(jié)構(gòu)
【內(nèi)存緩存 沙盒緩存】
-
磁盤緩存(沙盒緩存)
- 保存到內(nèi)存緩存中的字典是變量,程序退出后就不存在了
- 當(dāng)圖片下載完成之后,除了保存到內(nèi)存緩存中之外,還需要保存一份到磁盤緩存中
- 當(dāng)圖片需要顯示的時(shí)候,先檢查內(nèi)存緩存,如果內(nèi)存緩存中有數(shù)據(jù),那么就直接設(shè)置數(shù)據(jù)
- 如果內(nèi)存緩存中沒有數(shù)據(jù),那么再去檢查磁盤緩存
- 怎么檢查磁盤緩存?
- 看路徑對應(yīng)的文件是否存在
- 檢查磁盤緩存dataWithContentOfFile:
- 怎么檢查磁盤緩存?
- 如果磁盤緩存中有數(shù)據(jù),就直接設(shè)置就可以了 ,保存一份到內(nèi)存緩存中
- 顯示圖片
- 保存一份到內(nèi)存緩存中setObject:forKey
- 如果沒有數(shù)據(jù),再去下載數(shù)據(jù)
-
保存到磁盤的哪里?
- Documents:備份,不允許存緩存
- Library
- caches:緩存文件一般存到這里
- preference:偏好設(shè)置
- tmp:臨時(shí)路徑,隨時(shí)可能被刪除
-
步驟
- 獲得緩存路徑NSSearchPathForDirectorieesInDomains()
- NSCachesDirectory
- NSUerDomainMask
- YES
- lastObject
- 文件名稱
- NSURL拿到路徑的最后一個(gè)節(jié)點(diǎn)
- lastPathComponent
- 拼接全路徑
- 文件路徑+文件名稱
- stringByAppendingPathComponent:
- 寫文件
- 圖片是不能直接寫文件的,數(shù)組和字典可以寫文件
- 拿到圖片的二進(jìn)制數(shù)據(jù)
- data writeToFile:atomically:
- 獲得緩存路徑NSSearchPathForDirectorieesInDomains()
開子線程下載圖片
- 創(chuàng)建隊(duì)列NSOperationQueue
- 封裝操作
- NSBlockOperation blockOperationWithBlock:
- 添加操作到隊(duì)列
- UI刷新操作放到主線程
- NSOperation mainQueue]addOperationWithBlock
- 注意:在cellForRow中方法中創(chuàng)建了很多Queue,所以,定義一個(gè)屬性,懶加載中創(chuàng)建隊(duì)列
- 問:為什么圖片不顯示?只有cell滾動(dòng)的時(shí)候才能顯示?
- 最開始的時(shí)候圖片的尺寸為0,imageView的大小是根據(jù)圖片執(zhí)行的
- 操作是異步執(zhí)行的,當(dāng)cell要顯示的時(shí)候調(diào)用cellForRow設(shè)置圖片,開子線程下載是異步執(zhí)行的,可以先跳過代碼塊,回過頭來再執(zhí)行
- 解決:重新刷新,不能刷新整個(gè)tableView
- 刷新一行reloadRowsAtIndexPaths:withRowanimation:
完善
模擬下載該圖片需要花費(fèi)較長的時(shí)間,模擬網(wǎng)絡(luò)不好的情況
-
bug:圖片又重復(fù)下載
- 分析:如果cell的第0個(gè)圖片下載需要10s,在下載到第三秒的時(shí)候,拖動(dòng)cell,第0行cell放到了緩存池中,當(dāng)繼續(xù)拖動(dòng)cell,第0個(gè)cell又要顯示的時(shí)候,又開始重新下載圖片
- 先檢查圖片的下載操作是否已經(jīng)存在
- 存在:等待
- 不存在:封裝圖片下載操作并且添加到隊(duì)列
- 怎么判斷不存在?嘗試去取download
NSBlockOperation * download = [self.operations objectForKey:appM.icon]
- 怎么判斷不存在?嘗試去取download
-
bug:當(dāng)數(shù)據(jù)錯(cuò)亂的時(shí)候,程序容易崩潰
- 數(shù)據(jù)后臺(tái)傳給我們的,當(dāng)數(shù)據(jù)不對的時(shí)候,程序就會(huì)出現(xiàn)問題,會(huì)崩掉
- 原因:把圖片保存到內(nèi)存緩存的時(shí)候,image是空[self.images setObject:image forKey:appM.icon];image為nil,字典里面是不能保存空值的
- 解決:在設(shè)置之前判斷image有沒有值
-
bug:刷新tableView,數(shù)據(jù)錯(cuò)亂,顯示圖片和標(biāo)題不對應(yīng)
- cell復(fù)用的問題
- 兩種方法解決數(shù)據(jù)錯(cuò)亂問題
- 直接清空cell.imageView.image = nil,這樣做法會(huì)給用戶一種錯(cuò)覺,會(huì)認(rèn)為cell本身沒有圖片
- 設(shè)置一個(gè)占位圖片,先搞一個(gè)本地的圖片cell.imageView.image = [UIImage imageName:]
bug:圖片沒有下載圖片沒有下載成功,下載要顯示的時(shí)候,要嘗試重新下載,還需要把它從緩存中移除if(image ==nil){
//從緩存池中移除
[self.operations removeObjectForKey]
return;
}還需要細(xì)節(jié)的bug需要處理
SDWebImage實(shí)現(xiàn)
專門處理圖片下載和圖片緩存的
為Cocoa Touch框架提供一個(gè)UIImageView分類,加載圖片進(jìn)行緩存處理
異步圖片下載
異步存儲(chǔ)+具備自動(dòng)緩存過期的磁盤映像緩存
支持GIF播放
支持WebP格式
背景圖像壓縮
保證同一個(gè)url圖片資源不被多次下載
保證錯(cuò)誤url圖片資源不被多次下載
保證不會(huì)阻塞主線程
高性能
使用GCD和ARC
支持arm64架構(gòu)
面試:框架內(nèi)部實(shí)現(xiàn)細(xì)節(jié)
中文文檔SDWebImage-About框架的注釋
-
SDWebImage
- 改造多圖下載項(xiàng)目
- 一行代碼
- cell.imageView sd_setImageWithURL:placeholderImage:設(shè)置圖片
- 內(nèi)部做了內(nèi)存緩存和磁盤緩存
- 圖片尺寸的問題:
- 框架本身的問題
- 自定義cell里面設(shè)置圖片的frame
- layoutSubviews
- 開發(fā)中cell一般都需要自定義,就可以在xib上設(shè)置frame了