0
Help us understand the problem. What are the problem?

posted at

updated at

【非同期処理】UITableViewが`Index out of range`でクラッシュする回避策

環境

・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`が発生する
  }
}

原因

非同期でデータを受け取る前(配列がまだ空)にcellForRowAtdidSelectRowAtが呼ばれて、存在しない要素にアクセスしたため。

回避策

下記のように、配列が空の時は早期リターンでアクセスしないようにすることで回避できます。

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
}

Register as a new user and use Qiita more conveniently

  1. You can follow users and tags
  2. you can stock useful information
  3. You can make editorial suggestions for articles
What you can do with signing up
0
Help us understand the problem. What are the problem?