聊聊iOS中UITableView複用的那些事

語言: CN / TW / HK

theme: smartblue

持續創作,加速成長!這是我參與「掘金日新計劃 · 6 月更文挑戰」的第1天,點擊查看活動詳情

今天跟大家聊聊在開發中我們所遇到的tableView複用的那些事,相信大家在使用tableView或者collectionView時,都會遇到cell複用導致UI錯亂。在這篇文章中,我總結了一下幾點。

UITableView中的複用機制,想必大家應該都很清楚了。這裏就先簡單提一下:

tableview新建的時候,會新建一個複用池(reuse pool)。這個複用池可能是一個數組,或者是一個鏈表,保存着當前的cell。pool中的對象的複用標識符就是reuseIdentifier,標識着不同的種類的cell。調用dequeueReusableCellWithIdentifier:方法獲取cell。從pool中取出來的cell都是tableview展示的原型。無論之前有什麼狀態,全部都要設置一遍。

這裏我們就不對tableview的複用機制過多的探討,只講講平時開發容易忽略的複用的問題。

我列舉了以下幾種情況:

  • 在cell中條件判斷沒有覆蓋全場景
  • 在cell中使用了延遲或者異步處理
  • 在cell中UIImageView混用了網絡圖片和本地圖片

在更新cell的條件判斷沒有覆蓋全場景,只處理了某種條件下UI,其他的沒有處理

if xx { aLabel.isHidden = true avatarView.isHidden = false } else if xx { aLabel.isHidden = false avatarView.isHidden = true } else { aLabel.isHidden = true } 在某些時候,cell可能會用來兼容很多情況,或者某一個的cell有很多狀態,有時候因為疏忽導致沒有處理全部的情況,常常出現了不該顯示的UI元素顯示出來了。

因為tableview中的cell在使用標識符之後就會被複用,那麼我們就需要針對複用的cell去做格式化處理。比如每次刷新時,重製狀態。這樣就可以保證它的狀態是正常的,而不是上一次遺留的。

在cell中的使用了延遲或者異步處理

if xx { DispatchQueue.main.asyncAfter(deadline: .now() + 1) { avatarView.image = UIImage.init("123") } } else { xxxx } 有些時候,在cell中使用了延遲來處理某些邏輯。比如使用GCD或者異步回調來更新UI上的顯示,可能會有tableView刷新時複用問題,所以在使用延遲時,需要格外注意延遲後的邏輯判斷,在重新刷新時取消延遲處理或異步操作。

在cell中使用UIImageView加載網絡圖片和本地圖片

if xx { avatarView.image = UIImage.init("123") } else { avatarView.kf.setImage(with: url) } 在cell中我們會經常使用到網絡圖片加載庫來加載網絡圖片。在某些場景下,我們會將某個UIImageView既用來加載網絡圖片,也用來加載本地圖片。如果有使用場景下我們將一個控件用來處理本地、網絡兩種情況,那麼需要注意,再給加載本地圖片時取消網絡圖片的下載 sd_cancelCurrentImageLoad,或者不要使用同一個控件來加載網絡、本地圖片;

原因:加載本地圖片是同步進行的,而加載網絡圖片是異步的,有可能我們在刷新時,加載本地圖片。但是上次加載的網絡圖片還未加載完,這時,如果等上次的網絡圖片加載完成後,那麼這個圖片就會造成複用了。

總結下來,容易被忽視的其實還是在cell中有異步的操作。