多圖下載

多圖下載綜合案例

  • 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值
  • 嘗試去字典里去取值,用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:

開子線程下載圖片

  • 創(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]
  • 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了
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容