iOS中idx超63000时字符串追加触发EXC_BAD_ACCESS错误求解决方案
问题分析与优化方案
核心问题排查
你遇到的EXC_BAD_ACCESS错误,即使注释掉data_string相关操作仍会出现,说明问题根源不在字符串拼接本身,大概率是以下几点:
- 对
accelerometerData的强制解包(!)可能在某些边界场景下触发隐式内存访问异常 - 遍历超大量数据时,临时对象未及时释放,造成栈/堆内存溢出
sendFile如果是异步操作,可能和文件写入操作产生资源竞争
优化实现方案
1. 安全处理数据源,避免强制解包
先对accelerometerData做可选绑定,彻底消除强制解包带来的潜在崩溃风险:
guard let accelerometerData = recorder.accelerometerData(from: startOfDay, to: Date()) else { print("未获取到加速度数据") return }
2. 改用文件句柄直接写入,彻底规避内存累积
放弃字符串拼接累积的方式,直接用FileHandle逐段写入文件,从根源上避免大字符串占用内存:
var currentFileHandle: FileHandle? var currentBatchId = 0 for (idx, data) in accelerometerData.enumerated() { guard let accData = data as? CMRecordedAccelerometerData else { continue } let line = "\(timestamp), \(accData.acceleration.x)\n" guard let lineData = line.data(using: .utf8) else { continue } // 每45000条数据切换新文件 if idx % 45000 == 0 { // 关闭之前的文件句柄 currentFileHandle?.closeFile() // 创建新文件 currentBatchId = idx let batchFileName = "\(fileName)-\(currentBatchId)" let fileURL = DocumentURL.appendingPathComponent(batchFileName).appendingPathExtension("txt") // 初始化空文件 try? Data().write(to: fileURL) // 打开文件句柄准备写入 currentFileHandle = try? FileHandle(forWritingTo: fileURL) } // 写入当前行数据 currentFileHandle?.write(lineData) // 批次完成后发送文件(确保是批次最后一条数据再执行) if idx % 45000 == 44999 { guard let targetFileURL = currentFileHandle?.fileURL else { continue } sendFile(file_path: targetFileURL as NSURL) } } // 处理最后一批不足45000条的数据 if let finalFileURL = currentFileHandle?.fileURL { currentFileHandle?.closeFile() sendFile(file_path: finalFileURL as NSURL) }
3. 添加自动释放池,及时回收临时对象
在循环内部嵌入autoreleasepool,帮助系统及时回收循环中创建的临时对象,避免内存持续累积:
for (idx, data) in accelerometerData.enumerated() { autoreleasepool { guard let accData = data as? CMRecordedAccelerometerData else { return } let line = "\(timestamp), \(accData.acceleration.x)\n" guard let lineData = line.data(using: .utf8) else { return } // 后续文件写入逻辑... } }
4. 校验sendFile的执行时机
如果sendFile是异步操作,必须确保文件写入完成后再触发发送,避免文件未写完就被读取。可以将sendFile改为带回调的异步实现,或者在文件句柄关闭后再执行发送。
关键优化点总结
- 用文件句柄直接写入替代字符串累积,彻底解决大内存占用问题
- 全流程使用可选绑定,消除强制解包的崩溃风险
- 加入自动释放池,主动回收循环内临时对象
- 确保文件操作与发送操作的顺序性,避免资源竞争
内容的提问来源于stack exchange,提问作者Henryk Borzymowski
相关产品推荐
相关产品推荐

