在我們使用sd的時候,對tableView 上cell得圖片進(jìn)行異步下載的時候會遇到這樣一個問題:
由于cell的重用機(jī)制,在我們加載出一個cell的時候imageView數(shù)據(jù)源開啟一個下載任務(wù)并返回一個image,當(dāng)cell重用時,其數(shù)據(jù)源又會開啟一個下載任務(wù)下載新的image,但關(guān)聯(lián)的對象是同一個imageView,這個時候直接setImage時會發(fā)生錯亂。
SDWebImage的處理是:
imageView對象會關(guān)聯(lián)一個下載列表(列表是給AnimationImages用的,這個時候會下載多張圖片),當(dāng)tableview滑動,imageView重設(shè)數(shù)據(jù)源(url)時,會cancel掉下載列表中所有的任務(wù),然后開啟一個新的下載任務(wù)。這樣子就保證了只有當(dāng)前可見的cell對象的imageView對象關(guān)聯(lián)的下載任務(wù)能夠回調(diào),不會發(fā)生image錯亂。
同時,SDWebImage管理了一個全局下載隊(duì)列(在DownloadManager中),并發(fā)量設(shè)置為6.也就是說如果可見cell的數(shù)目是大于6的,就會有部分下載隊(duì)列處于等待狀態(tài)。而且,在添加下載任務(wù)到全局的下載隊(duì)列中去的時候,SDWebImage默認(rèn)是采取LIFO(last in,first out)策略的,具體是在添加下載任務(wù)的時候,將上次添加的下載任務(wù)添加依賴為新添加的下載任務(wù)。(在SDWebImageDownloader的callback中有這樣一段代碼):
[wself.downloadQueue addOperation:operation];
if (wself.executionOrder == SDWebImageDownloaderLIFOExecutionOrder) {
// Emulate LIFO execution order by systematically adding new operations as last operation's dependency
[wself.lastAddedOperationaddDependency:operation];
wself.lastAddedOperation = operation;
}
另外一種解決方案是:
imageView對象和圖片的url相關(guān)聯(lián),在滑動時,不取消舊的下載任務(wù),而是在下載任務(wù)完成回調(diào)時,進(jìn)行url匹配,只有匹配成功的image會刷新imageView對象,而其他的image則只做緩存操作,而不刷新UI。
同時,仍然管理一個執(zhí)行隊(duì)列,為了避免占用太多的資源,通常會對執(zhí)行隊(duì)列設(shè)置一個最大的并發(fā)量。此外,為了保證LIFO的下載策略,可以自己維持一個等待隊(duì)列,每次下載任務(wù)開始的時候,將后進(jìn)入的下載任務(wù)插入到等待隊(duì)列的前面。