Edited at

[iOS]UITableViewで、reloadData完了を検知する ※注意:追記あり


これまで

tableview.reloadData()

としたとき、内部的にわずかですがreloadData完了に時間がかかります。

なので

tableView.reloadData()

//reloadData()後を前提とした処理

とやってしまうと意図しない動作になります。

特にcellForRowAtIndexPathが呼ばれる前に処理すると最悪クラッシュしたりします。

それで今までは

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {

// indexPathが、tableView.indexPathsForVisibleRowsの最後のセルなら読み込み完了とする
}

などとすることがありました。

これはUITableViewのライフサイクル的に


func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
// ↓
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)
// ↓
func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath)

という流れだからですが、この方法にも問題があるようです。

(問題の内容については割愛)


iOS11から

tableView.performBatchUpdates({

self.tableView.reloadData()
}) { (finished) in
print("reload完了しました🙂")
}

こういう書き方ができるようです。

これはそもそもセルの挿入、移動、削除などを1回のアニメーションで行うためのメソッドです。

個人的にあまり馴染みがないメソッドなのですが、それもそのはずで、UITableViewに導入されたのはiOS11からで、元はUICollectionViewにあったもののようです。

公式

https://developer.apple.com/documentation/uikit/uitableview/2887515-performbatchupdates

https://developer.apple.com/documentation/uikit/uicollectionview/1618045-performbatchupdates

まあ何はともあれ、簡単にreloadData()終了を検知できるのは非常にありがたいです。

しかしUITableViewはiOS11からなので注意が必要です。

(UICollectionViewはiOS6からですが)


実際に使ってみる

普通のUITableViewです

Simulator Screen Shot - iPhone 8 Plus - 2018-10-26 at 16.15.15.png

更新を押しました

    didEndDisplaying section:2 row:3 

didEndDisplaying section:2 row:2
didEndDisplaying section:2 row:1
didEndDisplaying section:2 row:0
didEndDisplaying section:1 row:3
didEndDisplaying section:1 row:2
didEndDisplaying section:1 row:1
didEndDisplaying section:1 row:0
cellForRowAt section:0 row:3
willDisplay section:0 row:3
cellForRowAt section:1 row:0
willDisplay section:1 row:0
cellForRowAt section:1 row:1
willDisplay section:1 row:1
cellForRowAt section:1 row:2
willDisplay section:1 row:2
cellForRowAt section:1 row:3
willDisplay section:1 row:3
cellForRowAt section:2 row:0
willDisplay section:2 row:0
cellForRowAt section:2 row:1
willDisplay section:2 row:1
cellForRowAt section:2 row:2
willDisplay section:2 row:2
cellForRowAt section:2 row:3
willDisplay section:2 row:3
cellForRowAt section:3 row:0
willDisplay section:3 row:0
cellForRowAt section:3 row:1
willDisplay section:3 row:1
cellForRowAt section:3 row:2
willDisplay section:3 row:2
cellForRowAt section:3 row:3
willDisplay section:3 row:3
didEndDisplaying section:3 row:0
didEndDisplaying section:3 row:1
didEndDisplaying section:3 row:2
didEndDisplaying section:3 row:3
didEndDisplaying section:0 row:3
didEndDisplaying section:1 row:0
didEndDisplaying section:1 row:0
reload完了しました🙂


追記:??動かないパターンが有る?? 🤔

これはUICollectionViewの方ですが、動いた!って言う人と動かないって言う人がいますね

https://stackoverflow.com/questions/14020027/how-do-i-know-that-the-uicollectionview-has-been-loaded-completely

そもそもreloadってUpdatesの中でやらないとマズイんじゃないですかね?

ひょっとしたら罠があるかもしれません。何か分かったら追記します。


別解

reloadData処理後に処理を行いたい