環境
・Swift 5.5.2
・Xcode 13.2.1
発生したエラー
※一部コードを省略しています
ViewController.Swift
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.users = []
db.fetchUsers { [weak self] result in
guard let self = self else { return }
switch result {
case .success(let users):
self.users = users
case .failure(let error):
print(error.localizeddescription)
}
}
}
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! UITableViewCell
cell.configure(user: users[indexPath.row]) //この行で`index out of range`が発生する
return cell
}
}
extension ViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("indexpath.row: \(users[indexPath.row])") //タップした時にこの行で`index out of range`が発生する
}
}
原因
非同期でデータを受け取る前(配列がまだ空)にcellForRowAt
やdidSelectRowAt
が呼ばれて、存在しない要素にアクセスしたため。
回避策
下記のように、配列が空の時は早期リターンでアクセスしないようにすることで回避できます。
ViewController.Swift
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! UITableViewCell
guard users.count > 0 else { return cell } //このコードを追加
cell.configure(user: users[indexPath.row])
return cell
}