iOS开发:UITableView单元格显示异常、Core Data加载数据索引越界求解决
问题修复方案
错误原因及修复点
- 「Index Out of Range」致命错误根源:
cellForRowAt方法中硬编码取goals[1],数组索引从0开始计数,当goals数组元素数小于2时直接触发越界,应替换为当前行对应的索引indexPath.row。
- 「Index Out of Range」致命错误根源:
- UITableView布局压缩问题根源:
heightForRowAt方法返回值设置错误,当前返回的是goals数组的元素个数,比如只有1条数据时行高仅为1pt,自然会出现压缩无法显示的问题,需要将行高改为固定合理值,或者开启自动行高适配自定义Cell布局。
- UITableView布局压缩问题根源:
- 数据刷新逻辑缺陷:当前仅当
goals不为空时才调用reloadData,如果所有数据被清空,TableView不会同步更新为空状态,建议去掉判断直接刷新。
- 数据刷新逻辑缺陷:当前仅当
- 遗漏必实现的TableView数据源方法:你没有贴出
numberOfRowsInSection方法的实现,该方法必须返回goals.count才能正确渲染对应数量的Cell。
- 遗漏必实现的TableView数据源方法:你没有贴出
- addNewViewController代码小问题:
addNewAction方法定义后缺失左大括号,会触发编译错误。
- addNewViewController代码小问题:
修正后的代码示例
ViewController
var goals: [NSManagedObject] = [] // 新增必实现的行数设置方法 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return goals.count } // 行高设置修改 func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { // 可根据自己的Cell设计调整数值,或者用自动行高 return 80 } // Cell渲染修改 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! AllGoalsTableViewCell // 替换为当前行对应的索引 let goal = goals[indexPath.row] cell.titleLabel?.text = goal.value(forKey: "title") as? String return cell } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return } let managedContext = appDelegate.persistentContainer.viewContext let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "Goal") do { goals = try managedContext.fetch(fetchRequest) } catch let error as NSError { print("Could not fetch. \(error), \(error.userInfo)") } // 去掉非空判断,无论数据是否为空都刷新 tableView.reloadData() } // 如果要使用自动行高,在viewDidLoad中添加以下设置 override func viewDidLoad() { super.viewDidLoad() tableView.rowHeight = UITableView.automaticDimension tableView.estimatedRowHeight = 80 }
addNewViewController
var goals: [NSManagedObject] = [] func save(title: String, goalAmount: Double, percent: Double, amountPerWeek: Double) { guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return } let managedContext = appDelegate.persistentContainer.viewContext let entity = NSEntityDescription.entity(forEntityName: "Goal", in: managedContext)! let goal = NSManagedObject(entity: entity, insertInto: managedContext) goal.setValue(title, forKey: "title") goal.setValue(goalAmount, forKey: "goalAmount") goal.setValue(percent, forKey: "percent") goal.setValue(amountPerWeek, forKey: "amountPerWeek") do { try managedContext.save() goals.append(goal) } catch let error as NSError { print("Could not save. \(error), \(error.userInfo)") } } // 补全缺失的大括号 @IBAction func addNewAction(_ sender: Any) { self.save(title: title, goalAmount: goalAmount ?? 0.0, percent: percent, amountPerWeek: amountPerWeekFloat ?? 0.0) print("saved") }
额外注意点
自定义AllGoalsTableViewCell需要在Storyboard/Xib中设置好内部控件的上下左右约束,保证控件可以撑开Cell高度,自动行高才能生效。
内容的提问来源于stack exchange,提问作者Concon23a
相关产品推荐
相关产品推荐

