環境
Xcode: Version 11.3.1 (11C505)
Swift: 5
iOS: 13.2
執筆きっかけ
先輩から「その方法ではUICollectionViewの場合はクラッシュするよ」と指摘されたので検証する
その当時のフォールバック方法
*一部省略しております
final class TableViewController: UIViewController {
var mockError: String? // エラーを模しています
private lazy var tableView: UITableView = {
・・・
・・・
tableView.register(UITableViewCell.self, forCellReuseIdentifier: NSStringFromClass(UITableViewCell.self))
return tableView
}()
・・・
・・・
}
extension TableViewController: UITableViewDataSource {
・・・
・・・
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard mockError != nil else {
return UITableViewCell() // これが実行される
}
return tableView.dequeueReusableCell(withIdentifier: NSStringFromClass(UITableViewCell.self), for: indexPath)
}
}
上記の場合,mockErrorがnilであるため,
guard mockError != nil else {
return UITableViewCell()
}
が実行されます.これは,Errorが発生した想定です.
TableViewの場合は,registerされていないCellを返してもクラッシュしません.
UICollectionViewの場合
*一部省略しております
final class CollectionViewController: UIViewController {
private lazy var collectionView: UICollectionView = {
・・・
・・・
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: NSStringFromClass(UICollectionViewCell.self))
return collectionView
}()
var mockError: String?
・・・
・・・
}
extension CollectionViewController: UICollectionViewDataSource {
・・・
・・・
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard mockError != nil else {
return UICollectionViewCell() // これが実行される
}
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: NSStringFromClass(UICollectionViewCell.self), for: indexPath)
cell.backgroundColor = .black
return cell
}
}
先程のコードをUICollectionViewに置き換えてみました.
上記を実行すると...
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:'
上記の通り,UICollectionViewの場合は,registerしたCell以外を返すとクラッシュします
よって,下記の用に書き換えます
guard mockError != nil else {
return collectionView.dequeueReusableCell(withReuseIdentifier: NSStringFromClass(UICollectionViewCell.self), for: indexPath)
}
まとめ
今後TableViewの仕様が変わる可能性も考えて,フォールバック時にはregisterしたCellをどちらも返すようにします