iOS10からUITableViewのprefetchDataSourceというプロパティーが追加されてたので調べてみました。
prefetchDataSourceとは
prefetchDataSource
はUITableViewの高速化に使うプロパティーです。
下のようにUITableViewDataSourcePrefetching
に準拠したオブジェクトをセットして使います。
class MasterViewController: UITableViewController { override func viewDidLoad() { super.viewDidLoad() tableView.prefetchDataSource = self } } extension MasterViewController: UITableViewDataSourcePrefetching { func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) { } func tableView(_ tableView: UITableView, cancelPrefetchingForRowsAt indexPaths: [IndexPath]) { } }
tableView(_:prefetchRowsAt:)
はtableView(_:cellForRowAt:)
の前に呼ばれるので、サーバーからのデータ取得など時間のかかる処理を実施するのに適しています。
tableView(_:prefetchRowsAt:)の呼ばれるタイミング
実際にどのタイミングでtableView(_:prefetchRowsAt:)
が呼ばれるかも調べてみました。
調査は下のようにログをしかけて実施しました。
import UIKit class MasterViewController: UITableViewController { override func viewDidLoad() { super.viewDidLoad() tableView.prefetchDataSource = self } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 100 } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) cell.textLabel?.text = "\(indexPath)" print(#function, indexPath) return cell } } extension MasterViewController: UITableViewDataSourcePrefetching { func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) { print(#function, indexPaths) } func tableView(_ tableView: UITableView, cancelPrefetchingForRowsAt indexPaths: [IndexPath]) { print(#function) } }
アプリ起動時は下のようなログが出力されました。
tableView(_:prefetchRowsAt:)
はrowが13~22のCellのものが呼び出されている事が分かります。
rowが0~12のtableView(_:prefetchRowsAt:)
は呼ばれていないので、実装の際は注意する必要があります。
下へスクロールすると下のようなログが出力されました。
tableView(_:prefetchRowsAt:)
が呼ばれるのとセットでtableView(_:prefetchRowsAt:)
が呼ばれています。
上にスクロールすると下のようなログが出ました。
rowが13~15のtableView(_:prefetchRowsAt:)
が再度呼ばれていました。
まとめ
prefetchDataSource挙動に癖がありますが、うまく使えば便利そうだと感じました。
最近修正したアプリで「Cellの中でサーバーを画像を取得する」って事をやっていたので、そこで試してみようと思います。