tl;dr
1. dequeueReusableCell
の返り値をそのまま返す
更新できていないセルが表示されるのを許容できるならこの案が一番穏便だと思った.
2. nil
を返す
仕様的にキャストが失敗することはなさそうなので潔く落とすのもよさそう.
前提
状況
let dataSource = UICollectionViewDiffableDataSource<Int, UUID>(collectionView: collectionView) { (_, indexPath, _) in let cell = dequeueReusableCell(withReuseIdentifier: "customCell", for: indexPath) let customCell = cell as? CustomCell else { // ここでどうするか } // do something with customCell return customCell }
dequeueReusableCell(withReuseIdentifier:for:)
の仕様
引用元: dequeueReusableCell(withReuseIdentifier:for:)
スキーマは以下のようになっていて,
func dequeueReusableCell(withReuseIdentifier identifier: String, for indexPath: IndexPath) -> UICollectionViewCell
Return Valueの項にもこう書いてあるので,dequeueReusableCell
からは有効なUICollectionViewCell
が返ってきそう.
A valid UICollectionReusableView object.
ちなみに,返ってくるのは以前使ったセルか,それがなければ新しく作ったセル.
This method dequeues an existing cell if one is available or creates a new one based on the class or nib file you previously registered.
UICollectionViewDiffableDataSource.CellProvider
の仕様
引用元: UICollectionViewDiffableDataSource.CellProvider
定義は以下のようになっていて,
typealias UICollectionViewDiffableDataSource<SectionIdentifierType, ItemIdentifierType>.CellProvider = (UICollectionView, IndexPath, ItemIdentifierType) -> UICollectionViewCell?
返り値の型がUICollectionViewCell?
なのでnil
を返しても良さそうだが,Return Valueの項には以下のように書かれているのでnil
は返せなさそう.
A non-nil configured cell object. The cell provider must return a valid cell object to the collection view.
挙動の確認
1. dequeueReusableCell
の返り値をそのまま返す
先程のコードを使うと以下のようになる.
let dataSource = UICollectionViewDiffableDataSource<Int, UUID>(collectionView: collectionView) { (_, indexPath, _) in let cell = dequeueReusableCell(withReuseIdentifier: "customCell", for: indexPath) let customCell = cell as? CustomCell else { return cell // そのまま返す } // do something with customCell return customCell }
dequeueReusableCell
が返してくるのは以前使ったセルか,それがなければ新しく作ったセルなので更新されない状態のセルが表示されることになる.それ以外に問題はない.
2. nil
を返す
コードはこんな感じ.
let dataSource = UICollectionViewDiffableDataSource<Int, UUID>(collectionView: collectionView) { (_, indexPath, _) in let cell = dequeueReusableCell(withReuseIdentifier: "customCell", for: indexPath) let customCell = cell as? CustomCell else { return nil // nilを返す } // do something with customCell return customCell }
UICollectionViewDiffableDataSource.CellProvider
の定義どおり問題なくコンパイルは通るが,Return Valueの項にあったとおりnon-nilなセルを返さないといけないらしく,以下のような例外を吐いて死ぬ.
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'the collection view's data source did not return a valid cell from -collectionView:cellForItemAtIndexPath: for index path <NSIndexPath: 0x8d1687fd52393dda> {length = 2, path = 0 - 1}'
3. UICollectionViewCell()
を返す
例によって以下のようになる.もちろん返すのはCustomCell()
でもいい.
let dataSource = UICollectionViewDiffableDataSource<Int, UUID>(collectionView: collectionView) { (_, indexPath, _) in let cell = dequeueReusableCell(withReuseIdentifier: "customCell", for: indexPath) let customCell = cell as? CustomCell else { return UICollectionViewCell() // 新しくUICollectionViewCellを作って返す } // do something with customCell return customCell }
これもコンパイルは通るが以下のような例外を吐いて死ぬ.慈悲は無い.
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'the cell returned from -collectionView:cellForItemAtIndexPath: does not have a reuseIdentifier - cells must be retrieved by calling -dequeueReusableCellWithReuseIdentifier:forIndexPath:'
感想(結論ではない
1. dequeueReusableCell
の返り値をそのまま返す
UICollectionViewDiffableDataSource.CellProvider
でやりたいのは大体セルの更新だと思うので,更新できてないセルが表示されるのを許容できるならこの案が一番穏便だと思った.
2. nil
を返す
dequeueReusableCell
の仕様的にカスタムセルへのキャストが失敗することはなさそうなので,潔く落とすのもよさそう.
3. UICollectionViewCell()
を返す
わざわざインスタンスを作って落とすならnil
でいいじゃんという気がするのでこれはなし.