Swift中调用scrollToRow偶现Last Exception Backtrace(0)错误如何解决?
如何预防UITableView scrollToRow时的Last Exception Backtrace(0)错误
这个错误大概率是异步执行时UI/数据源状态不一致导致的——比如异步块触发时,TableView已被销毁、数据源已更新,或是计算出的IndexPath本身非法。以下是针对性的预防方案:
1. 先校验控制器与TableView的存活状态
异步块执行时,当前控制器可能已经被释放,直接调用scrollToRow会触发野指针类错误。通过弱引用+状态检查提前拦截:
DispatchQueue.main.async { [weak self] in guard let self = self else { return } // 确认TableView仍处于活跃状态(假设你的TableView属性名为tableView) guard self.tableView.window != nil else { return } let section = self.numberOfSections - 1 // 先判断section是否合法,避免出现负数 guard section >= 0 else { return } let row = self.numberOfRows(inSection: section) - 1 // 再判断row是否合法 guard row >= 0 else { return } let indexPath = IndexPath(row: row, section: section) if self.hasRowAtIndexPath(indexPath: indexPath) { self.scrollToRow(at: indexPath, at: .bottom, animated: isAnimated) } }
2. 修复IndexPath合法性校验逻辑
原代码直接用numberOfSections-1,如果numberOfSections为0会得到负数section,本身就是非法的。同时要确保hasRowAtIndexPath的实现严谨:
func hasRowAtIndexPath(indexPath: IndexPath) -> Bool { guard indexPath.section >= 0, indexPath.section < numberOfSections else { return false } guard indexPath.row >= 0, indexPath.row < numberOfRows(inSection: indexPath.section) else { return false } return true }
3. 避免数据源竞态问题
所有UITableView数据源的修改必须在主线程执行。如果异步块执行期间数据源可能被修改,建议在执行scrollToRow前重新计算row和section,不要复用之前的变量,确保和当前数据源状态匹配。
4. 异常捕获作为兜底方案
如果无法完全复现问题,可以给scrollToRow加异常捕获,避免崩溃扩散:
DispatchQueue.main.async { [weak self] in guard let self = self else { return } let section = self.numberOfSections - 1 guard section >= 0 else { return } let row = self.numberOfRows(inSection: section) - 1 guard row >= 0 else { return } let indexPath = IndexPath(row: row, section: section) if self.hasRowAtIndexPath(indexPath: indexPath) { do { try self.tableView.scrollToRowSafely(at: indexPath, at: .bottom, animated: isAnimated) } catch { // 记录日志用于后续排查 print("Scroll failed: \(error.localizedDescription)") } } } extension UITableView { func scrollToRowSafely(at indexPath: IndexPath, at scrollPosition: UITableView.ScrollPosition, animated: Bool) throws { guard indexPath.section < numberOfSections, indexPath.row < numberOfRows(inSection: indexPath.section) else { throw NSError(domain: "UITableViewError", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid IndexPath"]) } self.scrollToRow(at: indexPath, at: scrollPosition, animated: animated) } }
内容的提问来源于stack exchange,提问作者ppol2918
相关产品推荐
相关产品推荐

