しめ鯖日記

swift, iPhoneアプリ開発, ruby on rails等のTipsや入門記事書いてます

UITableViewのprefetchDataSourceについて調べてみる

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:)は呼ばれていないので、実装の際は注意する必要があります。

f:id:llcc:20180628141025p:plain

下へスクロールすると下のようなログが出力されました。
tableView(_:prefetchRowsAt:)が呼ばれるのとセットでtableView(_:prefetchRowsAt:)が呼ばれています。

f:id:llcc:20180628141143p:plain

上にスクロールすると下のようなログが出ました。
rowが13~15のtableView(_:prefetchRowsAt:)が再度呼ばれていました。

f:id:llcc:20180628141435p:plain

まとめ

prefetchDataSource挙動に癖がありますが、うまく使えば便利そうだと感じました。
最近修正したアプリで「Cellの中でサーバーを画像を取得する」って事をやっていたので、そこで試してみようと思います。