iOS开发:点击TableView单元格触发Thread 1: Fatal error: Index out of range错误的解决方法求助
解决TableView点击Cell时的Index Out of Range错误
这个错误的根源很明确:你的idArray和nameArray长度不一致,但TableView的行数是根据nameArray.count来返回的,当你点击某个Cell时,用indexPath.row去访问idArray的元素,就可能超出它的实际长度,触发越界崩溃。
为什么会出现数组长度不一致?
看你的getData()方法:
for result in results as! [NSManagedObject] { if let name = result.value(forKey: "name") as? String { self.nameArray.append(name) } if let id = result.value(forKey: "id") as? UUID { self.idArray.append(id) } }
这里是分开判断name和id是否存在,然后分别添加到数组里。如果某个CoreData的ToName对象只有name没有id,或者只有id没有name,那么其中一个数组就会比另一个多元素,最终导致两个数组长度不匹配。之前的应用没出错,大概率是因为当时的数据都同时包含name和id,所以数组长度始终一致。
解决方案(按推荐程度排序)
1. 使用自定义CoreData模型类(最推荐)
直接创建ToName的NSManagedObject子类,避免用字符串键取值,同时用单个数组存储对象,彻底解决数组同步问题:
- 打开CoreData模型文件,选中
ToName实体,点击Editor > Create NSManagedObject Subclass...,生成对应的子类文件。 - 修改你的ViewController代码:
// 替换原来的nameArray和idArray var patients = [ToName]() @objc func getData() { patients.removeAll() let appDelegate = UIApplication.shared.delegate as! AppDelegate let context = appDelegate.persistentContainer.viewContext let fetchRequest = ToName.fetchRequest() fetchRequest.returnsObjectsAsFaults = false do { patients = try context.fetch(fetchRequest) } catch { print("Fetch error: \(error)") } tableView.reloadData() } // 修改TableView数据源方法 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return patients.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = UITableViewCell() var content = cell.defaultContentConfiguration() content.text = patients[indexPath.row].name cell.contentConfiguration = content return cell } // 修改didSelectRowAt func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let selectedPatient = patients[indexPath.row] selectedName = selectedPatient.name ?? "" selectedId = selectedPatient.id performSegue(withIdentifier: "toNameVC", sender: nil) }
这样所有数据都封装在ToName对象里,完全不用担心数组长度不一致的问题,同时代码更简洁、安全,避免了字符串键的拼写错误。
2. 强制保证两个数组同步(临时方案)
如果暂时不想改模型类,就在getData()里确保每个CoreData对象要么同时添加到两个数组,要么都不添加:
for result in results as! [NSManagedObject] { if let name = result.value(forKey: "name") as? String, let id = result.value(forKey: "id") as? UUID { self.nameArray.append(name) self.idArray.append(id) } }
这样只有当name和id都存在时,才会添加到数组里,保证两个数组长度始终一致。
3. 添加边界检查避免崩溃(兜底方案)
在didSelectRowAt方法里先做边界判断,即使数组长度不一致也不会崩溃:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { guard indexPath.row < nameArray.count, indexPath.row < idArray.count else { print("Warning: Index out of bounds for nameArray or idArray") return } selectedName = nameArray[indexPath.row] selectedId = idArray[indexPath.row] performSegue(withIdentifier: "toNameVC", sender: nil) }
另外,还有两个关键小建议:
- 在
ToNameViewController的saveButton方法里,创建新对象时记得设置id属性!你现在只设置了name、tc、birth,没有设置id,这也是导致后续idArray可能缺少元素的原因之一:
newPatient.setValue(UUID(), forKey: "id") // 加上这行
- 避免用
as!强制类型转换,尽量用as?配合可选绑定,防止类型不匹配导致崩溃。
内容的提问来源于stack exchange,提问作者7mach
相关产品推荐
相关产品推荐

