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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 11:25:22