Swift代码触发SIGABRT信号崩溃排查(Core Data相关)
历史汇率获取代码崩溃(SIGABRT)排查与修复
核心崩溃原因
Core Data线程安全违规
你在URLSession.dataTask的后台线程闭包里直接操作了contextDataCore——默认情况下Core Data的上下文绑定主线程,后台线程直接读写主线程上下文会触发线程冲突,这是SIGABRT信号的主要来源。URL强制解包风险
URL(string: url)!用了强制解包,如果currentCurrency或fromCurrency包含特殊字符(比如空格、&等),URL构造会失败,直接触发崩溃。信号量释放路径不全
虽然大部分分支都调用了startupCheck_ExchangeRateFromPast.leave(),但如果contextDataCore.save()抛出错误,存在遗漏释放的风险。
修复后的代码
func downloadExchangeRateFromPast(toDate: Date, fromCurrency: String) { startupCheck_ExchangeRateFromPast.enter() let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yyyy-MM-dd" let fromDate = dateFormatter.string(from: toDate) // 对URL参数编码并可选绑定,避免强制解包崩溃 guard let encodedFromCurrency = fromCurrency.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed), let encodedCurrentCurrency = currentCurrency.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed), let url = URL(string: "https://api.exchangerate.host/convert?from=\(encodedCurrentCurrency)&to=\(encodedFromCurrency)&date=\(fromDate)") else { startupCheck_ExchangeRateFromPast.leave() return } let session = URLSession(configuration: .default) session.dataTask(with: url) { [weak self] (data, response, _) in // 用defer确保所有分支都释放信号量 defer { self?.startupCheck_ExchangeRateFromPast.leave() } guard let JSONData = data else { return } if let response = response as? HTTPURLResponse { print("Exchange Status: \(response.statusCode)") } do { let finalData = try JSONDecoder().decode(ExchangeRatePastJSON.self, from: JSONData) // Core Data操作切回主线程,保证线程安全 DispatchQueue.main.async { guard let self = self else { return } let newExchangeRate = ExchangeRateConvert(context: self.contextDataCore) newExchangeRate.date = toDate newExchangeRate.fromCode = fromCurrency newExchangeRate.toCode = self.currentCurrency newExchangeRate.rateConvert = finalData.result let newExchangeHistoryRecord = ExchangeHistoryRecord(context: self.contextDataCore) newExchangeHistoryRecord.finalRecord = "\(toDate) - \(fromCurrency) - \(self.currentCurrency)" do { try self.contextDataCore.save() } catch { print("Core Data保存失败: \(error)") } } } catch { print("JSON解码失败: \(error)") } } .resume() }
关键修复点说明
- 线程安全:把所有Core Data实体创建和保存操作放到
DispatchQueue.main.async里,确保主线程上下文只在主线程被操作;也可以根据业务需求创建私有队列上下文专门处理后台Core Data操作。 - URL安全处理:对货币代码做URL编码,避免特殊字符导致URL构造失败,同时用可选绑定替代强制解包。
- 信号量可靠释放:用
defer语句保证无论闭包里走哪个分支,信号量都会被释放,避免死锁或资源泄漏。
内容的提问来源于stack exchange,提问作者Travgalax
相关产品推荐
相关产品推荐

