Apple Watch上的CoreMotion OperationQueue问题

时间:2018-03-08 19:41:17

标签: swift memory-management apple-watch nsoperationqueue core-motion

设备:iPhone 8,Apple Watch Series 3

我目前正在开发一个手机app + watch扩展程序,它使用标准API和相关的OperationQueues从所有CoreMotion传感器传输CoreMotion数据。

我需要能够并行流式传输所有CoreMotion传感器,将样本写入csvs,然后导出它们。将样本存储在数组的内存中导致内存压力问题如预期的那样,所以现在我将每个样本直接写入文件,因此对于X =流式传感器,我也有X文件被写入,同样在关联的操作队列。

我的流媒体代码如下所示(例如对于加速):

public func start(mm: CMMotionManager, fileQueue: OperationQueue, myOutputURL: URL) {
    if mm.isAccelerometerAvailable && !mm.isAccelerometerActive {
        mm.startAccelerometerUpdates(to: sampleQueue, withHandler: { (sample: CMLogItem?, error: Error?) in
        if let error = error as NSError? {
            print("There was a sampling error --- \(error.localizedDescription)")
        } else {
            if let accelerometerData = sample as? CMAccelerometerData {
                let now = Date().timeIntervalSince1970
                let sampleComponents: [Double] = [
                    now,
                    accelerometerData.timestamp,
                    accelerometerData.acceleration.x,
                    accelerometerData.acceleration.y,
                    accelerometerData.acceleration.z
                ]
                let row = sampleComponents.map({ String(format: "%.5f", $0) })
                let sampleString = row.joined(separator: ",") + "\n"
                if FileManager.default.fileExists(atPath: myOutputURL.path)
                    let writeOperation = BlockOperation(block: {
                        do {
                            if let utf8Sample = sampleString.data(using: .utf8) {
                                let fileHandle = try FileHandle(forWritingTo: myOutputURL)
                                fileHandle.seekToEndOfFile()
                                fileHandle.write(utf8Sample)
                                fileHandle.closeFile()
                            }
                        } catch let error as NSError {
                            print("There was an error while writing to file --- \(error.localizedDescription)")
                        }
                    })
                    if let lastOperation = fileQueue.operations.last {
                        writeOperation.addDependency(lastOperation)
                    }
                    fileQueue.addOperation(writeOperation)
                    print("Num OPs in Sample Queue: \(sampleQueue.operations.count)")
                    print("Num OPs in I/O Queue: \(fileQueue.operations.count)")
                }
            }
        })
    }
}

这在手机上很棒......在任何给定时间,采样操作队列很少有超过100个总操作,并且文件最多排队5个 - 即使流式传输超过一个小时。但是,我在watchkit扩展中使用完全相同的代码来传输加速度和运动数据,并且会发生一些奇怪的事情。传感器数据的样本队列无限增加。换句话说,就好像来自CoreMotion采样的操作永远不会从采样队列中出列。

备注:除了依赖链之外,队列还配置为:

    sampleQueue.maxConcurrentOperationCount = 1
    fileQueue.maxConcurrentOperationCount = 1

希望样品按顺序接收和书写。

这种无限增加导致内存分配在大约15分钟的流式传输后接近80MB左右,我根据经验发现,由于压力太大,我的手表操作系统终止扩展时的上限。我记录了每个样本进入时样本队列中的操作数,当它接近80MB标记时,队列中有大约60-80k的操作,而在I / O队列中,数字类似于手机的那个。我无法理解为什么因为看起来更直观的是磁盘I / O队列中存在瓶颈而不是样本队列,特别是随着文件大小和样本数量的增加。

我很好奇其他人是否经历过这样的问题以及他们如何克服它,因为在从Apple设备存储和导出传感器数据时,这似乎是一个相当标准的问题。

具体来说,我很好奇其他人如何设法在这些设备上长时间传输和存储传感器数据以供以后分析,如果您觉得我正在做的事情是不正确的。非常感谢!

1 个答案:

答案 0 :(得分:0)

我认为关键是要在Watch本身上进行尽可能少的处理。

这不能直接解决问题,但是我所做的是将数据从Watch传输到iPhone,并在iPhone上完成了CSV处理。这样可以避免让手表进行繁重的工作(这对于旧款手表而言尤为重要)。

另外,您的updateInterval是什么?