升级Xcode 15后出现index out of range崩溃,求排查方案
可能的崩溃原因
index为负数
你当前只判断了texts.count > index,但如果index是负数(比如varData.value解析出-1),这个条件依然成立(比如数组长度为3时,3 > -1为true),但Swift数组不允许负数下标,直接访问就会触发越界崩溃。之前没出现可能是测试数据未覆盖负数场景,升级Xcode后编译器优化让这个问题暴露出来。多线程并发修改数组
如果varData.texts在其他线程被修改,比如在执行texts.count > index之后、访问texts[index]之前,数组元素被移除导致长度变小,此时index就会超过新的数组下标范围。本地难以复现是因为并发场景具有随机性。Xcode15编译器优化潜在问题
Xcode15搭载的Swift 5.9编译器有新的优化逻辑,可能对可选绑定、条件判断的执行顺序做了重排,或者编译器假设数组不会被修改,导致边界检查和数组访问的逻辑出现偏差。这种情况相对少见,但也是可能的诱因。
针对性解决方案
修复负数index问题
在条件判断中新增index >= 0的检查,同时用index < texts.count替代texts.count > index(逻辑等价,但结合非负判断更直观),确保下标在合法范围内:if let firstEnum = stateActions.first(where: { $0.type == .enumVar }){ if let arg = firstEnum.arg, arg.count > 2, variableDataDict.keys.contains(firstEnum.endpoint), let varData = variableDataDict[firstEnum.endpoint], let index = varData.value as? Int, let texts = varData.texts, index >= 0, index < texts.count { let text = texts[index] buttonText += "\n" + text } }解决并发修改问题
如果数组存在多线程修改的可能,访问时先复制一份数组,避免原数组在判断和访问之间被修改:if let firstEnum = stateActions.first(where: { $0.type == .enumVar }){ if let arg = firstEnum.arg, arg.count > 2, variableDataDict.keys.contains(firstEnum.endpoint), let varData = variableDataDict[firstEnum.endpoint], let index = varData.value as? Int, let texts = varData.texts, index >= 0, index < texts.count { let safeTexts = texts // 复制数组,隔绝原数组的修改影响 let text = safeTexts[index] buttonText += "\n" + text } }验证编译器优化问题
可以临时关闭编译器优化来验证:在Xcode的Build Settings中,将Optimization Level改为None [-O0],重新打包TestFlight测试。如果崩溃消失,说明是编译器优化导致的问题,可提交Bug给Apple,同时暂时用上述复制数组的方式规避。
内容的提问来源于stack exchange,提问作者Michael J

