You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift数组随机崩溃求助:_checkInoutAndNativeTypeCheckedBounds报错

数组操作随机崩溃:索引越界与遍历逻辑错误分析

我这段代码会随机崩溃,报错信息是:Swift._ArrayBuffer._checkInoutAndNativeTypeCheckedBounds (Swift.Int, wasNativeTypeChecked : Swift.Bool) -> ()。调试时打印index居然得到异常结果:(lldb) po index (Function)。我以为用了queue.sync就能避免并发修改问题,但还是崩溃了,到底哪里错了?

代码如下:

func addAfterDeletingPrexisting(type: InsightType, value: [String: Any]) {
    arrayUpdationQueue.sync {
        let insightsLocal = insights
        var outputInsights = insights
        for (offset: index, element: (key: key, value: _)) in insightsLocal.enumerated() {
            if key == type {
                outputInsights.remove(at: index) // 此处崩溃
            }
        }
        insights = outputInsights
        self.insights.append((key: type, value: value))
    }
}

核心问题:遍历原数组索引删除副本元素导致的越界崩溃

你看到的index显示为Function大概率是调试器的显示异常,真正的崩溃原因是数组索引越界。

具体来说:

  • 你先创建了原数组insights的副本insightsLocal和outputInsights
  • 遍历insightsLocal的索引和元素,当找到匹配的type时,直接删除outputInsights对应索引的元素
  • 问题出在:如果原数组中有多个匹配的元素,第一次删除会让outputInsights的长度减1,但后续遍历的索引还是基于原数组的长度。比如原数组长度是3,删除索引0后,outputInsights长度变成2,这时候再尝试删除原数组的索引2,就会超出outputInsights的有效索引范围(最大索引是1),直接触发越界崩溃。

另外,你用queue.sync确实能保证这段代码的串行执行,避免并发修改insights的问题,但这和当前的崩溃无关——崩溃是遍历删除的逻辑错误导致的,不是并发问题。

解决方案:用过滤替代遍历删除,或倒序删除索引

最简洁且安全的方式是使用filter直接过滤掉不需要的元素,完全避免索引操作:

func addAfterDeletingPrexisting(type: InsightType, value: [String: Any]) {
    arrayUpdationQueue.sync {
        // 直接过滤掉所有key等于type的元素
        let filteredInsights = insights.filter { $0.key != type }
        insights = filteredInsights
        insights.append((key: type, value: value))
    }
}

如果一定要用遍历删除的方式,需要先收集所有要删除的索引,然后倒序删除(避免前面的删除影响后面的索引有效性):

func addAfterDeletingPrexisting(type: InsightType, value: [String: Any]) {
    arrayUpdationQueue.sync {
        let insightsLocal = insights
        var outputInsights = insights
        // 收集所有需要删除的索引
        var indicesToRemove = [Int]()
        for (index, element) in insightsLocal.enumerated() {
            if element.key == type {
                indicesToRemove.append(index)
            }
        }
        // 倒序删除,避免索引偏移
        for index in indicesToRemove.reversed() {
            outputInsights.remove(at: index)
        }
        insights = outputInsights
        self.insights.append((key: type, value: value))
    }
}

额外优化:简化变量操作

你可以把insights = filteredInsights和append合并成一行,让代码更简洁:

insights = filteredInsights + [(key: type, value: value)]

内容的提问来源于stack exchange,提问作者Nikhil Manapure

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:22:05