iOS应用报com.apple.main-thread EXC_BREAKPOINT崩溃,collectionView刷新时出错
崩溃原因分析
- 索引默认值风险:代码中当
hostListUIArray中找不到对应userkey时,会给index赋值默认值0,如果此时数组非空,会错误刷新第0行,若此时第0行对应数据状态和collectionView数据源不匹配就会触发崩溃。 - 索引校验不全:仅校验了row在
hostListUIArray的索引范围内,未校验section 0是否真实存在,若当前collectionView的分组数小于1,哪怕row合法也会触发越界异常。 - 异步数据源不一致:从获取索引到执行刷新的异步时间差内,
hostListUIArray或collectionView的数据源可能已经被其他操作修改(例如删除元素、整体刷新),之前的合法索引在执行刷新时已经失效,触发崩溃。 - 补充前置风险:代码中
userDict["userType"] as! String使用了强制类型转换,若userType字段不存在或类型不为String时会提前触发崩溃。
可行修复方案
- 移除索引默认值,找不到对应
userkey时直接终止刷新逻辑,避免错误刷新非目标行。 - 补全索引校验逻辑,同时校验collectionView是否存在、section数量是否合法、对应section的行数是否大于目标索引,保证执行刷新时IndexPath完全合法。
- 所有数据源更新操作(包括
hostList、hostListUIArray的修改)统一放在主线程执行,避免多线程操作导致的数据源不同步问题。 - 替换强制类型转换为可选绑定,避免前置的类型转换崩溃。
修复后代码示例
if let userType = userDict["userType"] as? String, let _ = userDict["userID"], let _ = userDict["audioStatus"], let _ = userDict["ask"], userType == "Host" { let userkey = snapshot.key as? String ?? "" let keyExistsInHost = self.hostList[userkey] != nil if keyExistsInHost { userDict["isHighlighted"] = "No" as AnyObject // 数据源更新统一放在主线程,若本身已在主线程可省略DispatchQueue.main.async包裹 DispatchQueue.main.async { [weak self] in guard let self = self else { return } self.hostList.updateValue(userDict, forKey: userkey) // 此处需补充hostListUIArray和hostList的同步更新逻辑,保证UI数组和数据源一致 } DispatchQueue.main.async { [weak self] in guard let self = self, let collectionView = self.collectionView else { return } // 找不到对应key直接返回,不使用默认值 guard let index = self.hostListUIArray.firstIndex(of: userkey) else { return } // 校验section合法性 guard collectionView.numberOfSections > 0 else { return } // 校验对应section的行数合法性 guard collectionView.numberOfItems(inSection: 0) > index else { return } // 安全执行刷新 collectionView.reloadItems(at: [IndexPath(row: index, section: 0)]) } } }
内容的提问来源于stack exchange,提问作者Himani Patel
相关产品推荐
相关产品推荐

