Swift中Thread 1 signal SIGABRT循环崩溃问题求助
首先,咱们来拆解一下你遇到的问题:崩溃发生在第二次触发if条件时,定位在获取openOrderMutArray[j]的FIPS值那一行。结合代码来看,核心问题出在遍历可变数组的同时直接修改原数组,以及一些不安全的类型转换操作上。
崩溃的主要原因
遍历与修改可变数组的冲突:
你在遍历openOrderMutArray的同时,执行了openOrderMutArray.removeObject(at: j)和logOrderMutArray.add(openOrderMutArray[j])操作。虽然你手动调整了j -= 1,但logOrderMutArray是外层循环的遍历数组,往里面添加元素会导致外层循环的count动态变化,可能引发后续遍历的索引混乱。更关键的是,当openOrderMutArray元素被移除后,后续的j可能会超出数组当前的有效索引范围,触发越界崩溃。不安全的强制类型转换:
代码里多次使用as! NSDictionary这种强制解包操作,如果数组中存在非NSDictionary类型的元素,或者转换失败,会直接触发崩溃。另外,KVC调用value(forKey:)本身就不够安全,若对象没有对应的key,返回nil后虽然你做了默认值处理,但如果对象本身已经被释放,也会导致SIGABRT。
修复方案
方案1:改用Swift原生集合类型,避免NSMutableArray/NSDictionary
Swift的原生Array和Dictionary类型更安全,支持类型推断,能减少很多运行时错误。咱们把代码重构一下:
假设你的数组元素是[String: Any]类型,重构后的代码大概是这样:
func removeDuplicatesFromOrderAndOpenOrder() { var storedArray = [[String: Any]]() // 先复制一份openOrder数组,避免遍历原数组时修改导致的问题 var openOrders = openOrderMutArray as! [[String: Any]] var logOrders = logOrderMutArray as! [[String: Any]] for i in 1..<logOrders.count { // 直接跳过i=0,不用continue let orderFips = logOrders[i]["FIPS"] as? NSNumber ?? 0 let orderAccountNumber = logOrders[i]["AccountNumber"] as? String ?? "" // 倒序遍历openOrders,避免移除元素后索引混乱 for j in (0..<openOrders.count).reversed() { let fips = openOrders[j]["FIPS"] as? NSNumber ?? 0 let accountNumber = openOrders[j]["AccountNumber"] as? String ?? "" if orderFips == fips && orderAccountNumber == accountNumber { var editDict = logOrders[i] let newDict = openOrders[j] editDict["Inspectionlist"] = [newDict] logOrders[i] = editDict openOrders.remove(at: j) } else { storedArray.append(openOrders[j]) logOrders.append(openOrders[j]) } } } // 最后把修改后的数组赋值回原有的NSMutableArray logOrderMutArray = NSMutableArray(array: logOrders) openOrderMutArray = NSMutableArray(array: openOrders) }
方案2:如果必须使用NSMutableArray,避免遍历原数组
如果你因为历史原因必须保留NSMutableArray,那要遍历数组的副本,而不是原数组:
func removeDuplicatesFromOrderAndOpenOrder() { let storedArray = NSMutableArray() // 复制一份openOrder的副本用于遍历 let openOrderCopy = openOrderMutArray.mutableCopy() as! NSMutableArray for i in 0..<logOrderMutArray.count { if i == 0 { continue } let orderItem = logOrderMutArray[i] as! NSDictionary let orderFipsValue = orderItem.value(forKey: "FIPS") as? NSNumber ?? 0 let orderAccountNumberValue = orderItem.value(forKey: "AccountNumber") as? String ?? "" for j in (0..<openOrderCopy.count).reversed() { let openItem = openOrderCopy[j] as! NSDictionary let fipsValue = openItem.value(forKey: "FIPS") as? NSNumber ?? 0 let accountNumberValue = openItem.value(forKey: "AccountNumber") as? String ?? "" if orderFipsValue == fipsValue && orderAccountNumberValue == accountNumberValue { let editDict = orderItem.mutableCopy() as! NSMutableDictionary let newMutableArray = NSMutableArray(object: openItem) editDict.setValue(newMutableArray, forKey: "Inspectionlist") logOrderMutArray.replaceObject(at: i, with: editDict) openOrderMutArray.removeObject(at: j) openOrderCopy.removeObject(at: j) } else { storedArray.add(openItem) logOrderMutArray.add(openItem) } } } }
关键优化点
- 倒序遍历数组:当需要移除元素时,倒序遍历可以避免因为数组长度变化导致的索引偏移问题,不用手动调整
j的值。 - 使用数组副本遍历:避免修改原数组时影响遍历的索引范围,从根源上防止数组越界。
- 减少强制解包:尽量用
as?代替as!,如果必须强制解包,确保该元素一定是对应的类型,或者添加前置判断。
内容的提问来源于stack exchange,提问作者B.Saravana Kumar

