1.要解決的問題.緩存
給單元格設置從網絡上下載的圖片.網絡
2.思路:異步
>1.先同步下載佈局
bug:下載是一個耗時操做,會阻塞主線程優化
>2.異步下載圖片atom
bug:圖片發生錯行.url
>從網絡上請求下來的圖片與單元格不匹配.爲何會這樣?根本緣由是由於重用單元格.spa
如圖所示.線程
tableView上有3個單元格.每一個單元格有圖片,文字.文字是經過plist加載,當向上滾動單元格,讓,單元格1滾出界面,那麼就會加載第4個單元格,第四個單元格仍然是新建立的,由於當單元格1還沒有滾出視圖,單元格4已經出來一部分,是不可能重用的.當單元格4徹底加載出來,單元格1徹底滾出界面,緩存池中就有了可重用單元格,當加載第5個單元格,就不會重寫建立單元格,而是到緩存池中找,因而把第1個單元格,放到第5個單元格的位置,若是此時並不根據indexPath設置第五個單元格的數據,那麼就會發生單元格重用,第5個單元格和第1個單元格徹底同樣,所以,一般爲了解決單元格重用,須要根據indexPath從新設置單元格5的數據.code
由於從網絡上請求數據是比較耗時的,可能會發生這樣一種狀況:
單元格1的圖片還沒有請求到,就已經滾出界面,單元格5重用了單元格1的數據,經過根據indexPath獲取plist文件中對應的文字數據,能夠方式重用致使的問題.單元格一樣要發送請求到網絡上請求本身的圖片,可是若是單元格1請求圖片比較慢,那麼,單元格5會先設置本身的圖片,而後又設置單元格1的圖片,因而發生覆蓋.致使圖片與文字不匹配.
那麼plist設置文字會發生這種情況麼?首先,我以爲若是從plist文件中加載數據也像從網絡中請求數據那樣耗時,而且取不一樣的字符串耗時差距比較大,也會發生覆蓋問題.可是我以爲從本地取數據是很快的,而且,便是耗時,從plist中取一個長度爲10,和長度爲100的字符串也是差很少的.這種偏差一般應該不會發生
SDWebImage的解決方式,便是斬斷這種多個數據填一單元格的問題,當單元格已經出去了,卻沒有下載好圖片,那麼就取消單元格1的下載操做,因而滾到單元格5的時候,這個單元格就只有一個網絡請求,不會再有比它更慢的網絡請求的圖片回來覆蓋單元格5對應的正確的數據.
這種實現比較麻煩,先考慮簡單的解決方式.
方式1:並不直接將網絡請求的數據設置給單元格,而是經過給plist文件對應的模型增長一個屬性UIImage,由於模型數據老是一一對應的,由於角標不一樣,當單元格1的圖片數據請求回來,設置給模型中的image屬性,由於---------會不會發生這種狀況,將請求回來的圖片設置給模型的image屬性的時候發生錯亂?好比,單元格1請求數據比較慢,單元格3請求下來的數據設置給單元格1對應的image屬性?就目前這種寫法,應該不會,由於實際上,每次請求圖片都是新開了了線程,若是CPU分配,那麼每個單元格對應着一個線程,也就是單元格3請求數據和單元格1請求圖片和設置圖片是在不一樣線程,不會發生設想的問題.假設CPU並不讓每個單元格從新開線程,而是上一個執行完了再將新的任務添加到同一個線程中,也不會發生設想的這種錯亂.
由於設置數據的時候,是在子線程請求圖片的,於是能夠直接忽略該段代碼,於是會致使一個bug,圖片請求回來了,卻並無圖片,由於控件是懶加載,當第一次佈局單元格的時候,並無圖片請求回來,於是layoutSubViews不會佈局圖片框的位置,當滑動或者點擊單元格,又會調用layoutSubViews方法,此時系統意識到有圖片,於是會佈局圖片,該問題能夠經過佔位圖解決,
方式2:
思路和前面仍然是同樣,不直接將下載的數據和單元格關聯,經過一箇中介將下載的圖片和plist文件一一對應便可.字典是一一對應的,將模型中的url做爲鍵,(每一個單元格都不一樣,於是是惟一的),將圖片做爲值存儲起來.此時還須要在下載圖片前先從圖片緩存字典中取,若是有,就設置圖片,沒有就下載,也能夠解決錯行問題.SDWebImage只不過是經過NSCache解決的,實現思路也是同樣.而且NSCache其實和字典也差很少,只須要setObjectForKey存,ObjectForKey取便可.
>3.有網狀態下下載下來的圖片須要緩存到本地,這樣,當沒網,就能夠到緩存中取.數據本地化可使用歸檔或者plist,我用的是plist,注意,當沒有網的時候就能夠從沙盒中找.又因爲,從沙盒中取效率不如從內存中取高,當第一次從沙盒中加載,再次上下滑動時候,考慮從內存中去,因而能夠從沙盒中取出圖片後,同時將圖片設置給圖片緩存.又若是是第一次從網上加載,再次上下滑動,從沙盒中加載,不如直接從內存中加載效率高,考慮從網上下載後一樣設置給圖片緩存(內存).
>4.bug3,即便圖片下載下來了,可是再次滾動單元格仍是會再去下載,這顯示是不必的,我最初的想法是,給模型增長一個BOOL值,當任務被添加到隊列中,將BOOL值設置爲YES,表示正在下載,沒必要重複下載,實際上也是能夠解決問題的.可是又有一個問題.若是用戶清除緩存了,而且程序沒有掛掉,也就是說沙盒中,沒有圖片,那麼能夠去圖片緩存中取,若是從新運行程序,BOOL值又恢復爲nil,又從網上加載,貌似沒有問題.????爲啥還要移除操做緩存????有沒有這樣一種可能,BOOL值顯示爲正在下載,可是圖片緩存中沒有數據,沙盒中也沒有數據,可是又由於BOOL值顯示正在下載致使沒法再次下載???有可能,當收到內存警告,內存中被清空了,沙盒中又被清除緩存,模型中的BOOL值仍然顯示着正在下載,致使沒法再次下載.-----確實有問題,當收到內存警告,內存緩存中的圖片緩存會被清空,而且沙盒中也被清除緩存,此時操做緩存中顯示正在下載,不會再次下載,若是設置了佔位圖,就會發生只有佔位圖,若是沒有設置佔位圖,就會發生圖片複用.於是,當圖片下載完成,須要將操做緩存移除.
>5.經過BOOL值確實能夠解決重複下載的問題,可是呢,這樣會不會形成代碼的耦合性太高呢?假設須要將下載之外的事務抽取出來,不放在控制器中,專門封裝到一個管理者類中,操做緩存這一步該如何封裝進去?-----若是經過增長BOOL值記錄操做緩存,那麼須要用到模型,然而,管理者類中又用到模型,耦合性實在過高,故而此種作法很差.
>6.在增長新的東西前,先優化一下當前代碼,你不以爲設置單元格的方法太過於冗長了麼?怎麼抽取一下?...不管是抽取到自定義單元格中仍是抽取到一個單獨的方法,須要的參數都不少,暫時不這樣作.
>7.增長一個管理者類,將下載無關的業務邏輯抽取出來,須要在三個類之間進行傳值,能夠經過block解決.而且比較容易實現.須要注意一個問題
管理者類中用到了block,
typedef void(^giveImageToVc)(UIImage * image);
屬性
@property (nonatomic,copy) giveImageToVc giveImageToVc;
// 須要回到主線程操做. if (self.giveImageToVc) { self.giveImageToVc(img);//此處省略self,並不會報錯,由於,默認的識別爲起別名的block, } return ;
像這樣:
typedef void(^myblock)(UIImage *); - (void)test:(NSString *)urlString { myblock(abc);//而且括號中的參數寫什麼都不會報錯
>8.由於要仿SDWebImage,SDWebImage解決圖片錯行的方式和上面的方式稍稍不一樣,其思路是這樣的:
由於根本緣由在於多個請求填一個單元格,那麼當滾到新的單元格的時候,若是還有舊的單元格請求綁定着新的單元格,那麼只須要切斷就的請求便可.而且SDWebImage是經過給UIImageView添加分類的方式,於是我也這樣作,那麼在分類方法中就要作這幾件事:
仍然以上面的示例圖片爲例,假設單元格1已經滾出屏幕,單元格4滾入屏幕,那麼單元格4滾進屏幕,須要作這樣的判斷,判斷單元格1的圖片是否下載完成,若是已經完成,由於當下載完成了,就會執行設置圖片操做,由於覆蓋問題就是一方面是由於重用,一方面也是由於請求圖片比較耗時,若是單元格1已經下載完成,那麼單元格4下載圖片確定在其後,不會發生覆蓋.若是單元格1還沒有下載完成,那麼就有可能比單元格4下載慢,致使覆蓋
於是,若是知足當滾動到單元格4的時候,單元格1還沒有下載完成,那麼就取消單元格1的下載操做,執行單元格1的下載操做.
?問題1;如何斷定單元格1是否下載完成?
?問題2:由於要在分類中記錄單元格1的urlString,一般是經過屬性記錄,然而,分類是不能增長屬性的.可不能夠用靜態全局變量
?問題3:第一次進來,oldURLString 爲nil,將當前urlString賦值給oldURLString,第二次進來,存儲的是就是第一個單元格的urlString,界面上能顯示3個單元格,顯然此時單元格1和單元格2,3不會發生覆蓋問題,當加載第四個單元格的時候,須要判斷的是第一個單元格是否下載完成,那麼如何判斷當前滾動出來的單元格是界面中最底下的呢?
或者說加載第二個單元格時,第一個還沒有加載完,取消,這樣到加載第四個單元格的時候也不會發生多個數據搶一個單元格的問題.可是這樣太狠了,有一些操做是不必的,損耗效率的.思路有問題.....
由於加載每一個單元格都會調用分類方法,也就是說,只有當第一個單元格成爲第4個單元格的時候纔可能發生覆蓋問題,才須要判斷第一個單元格是否下載完成,那麼首先要判斷當前傳進來的URL是不是第四個,這樣有問題,若是屏幕顯示的圖片不止四個呢?屏幕顯示多少個單元格取決於單元格高度和手機屏幕,這些都是不可控制的.思路有問題.....
果真有問題
問題大大的