You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 16:12:49