Swift使用安全索引扩展访问数组偶发越界崩溃问题排查求助
问题根因
- 最高概率的触发原因是多线程数据竞争:你的
currentSamplesInShiftInterval属于可变集合,存在多线程同时读写的情况。Swift值类型的写入操作不是原子性的,当前线程读取数组的过程中,若刚好有其他线程执行数组的增删操作,会导致你读取到的数组处于中间不一致的损坏状态:你判断count>1时数组状态尚且正常,但执行安全下标访问时,数组的startIndex/endIndex已经被修改为异常值,直接越过了安全判断的边界校验,访问非法索引触发崩溃。 - 次要可能原因:你当前操作的是
ArraySlice(通过prefix/suffix/切片语法等方法生成的切片实例),切片的startIndex并非默认的0,结合索引计算逻辑出现异常触发越界。
修复方案
- 优先解决多线程竞态问题
所有对currentSamplesInShiftInterval的读写操作统一放在同一个串行调度队列中执行,保证同一时间只有一个操作访问数组,避免出现中间状态。如果需要跨线程访问,先拷贝一份不可变副本,后续所有逻辑都基于副本执行,避免操作过程中数组被修改:
// 先拷贝不可变副本,后续全操作副本 let samplesCopy = currentSamplesInShiftInterval if samplesCopy.count > 1 { guard let indexOfCurrentSample = samplesCopy.firstIndex(of: distanceSample) else { return } guard let priorSamplesEndDate = samplesCopy[safe: indexOfCurrentSample - 1]?.endDate else { return } }
- 优化安全下标扩展
针对数组等整数索引场景的校验逻辑,直接使用indices.contains替代手动边界判断,避免通用Collection扩展的潜在兼容问题:
// 针对整数索引的随机存取集合的安全下标 extension RandomAccessCollection where Index == Int { public subscript(safe index: Int) -> Element? { guard indices.contains(index) else { return nil } return self[index] } }
- 如果你操作的是数组切片,先转换为完整
Array后再执行索引相关操作,规避切片非零起始索引的问题:
let fullArray = Array(currentSamplesInShiftInterval) // 后续对fullArray执行操作
内容的提问来源于stack exchange,提问作者GarySabo
相关产品推荐
相关产品推荐

