我们的应用程序中有一个CMMotionManager实例,我们用它来获取频率为5Hz的传感器更新。以下是我们用于启动动画更新的代码:
[self.motionManager
startDeviceMotionUpdatesUsingReferenceFrame:
CMAttitudeReferenceFrameXMagneticNorthZVertical
toQueue:operationQueue
withHandler:^(CMDeviceMotion *motion, NSError *error) {
if (!error) {
[self doSomethingWithMotion:motion];
} else { ... }
总是在主线程上调用上述方法。
现在,一旦完成了我们的任务,我们再次在主线程上调用以下方法来停止动作更新:
- (void)stopMotionUpdates {
// This might get called on concurrent threads.
// So better using sync block + make it idempotent
@synchronized(self) {
if (_motionManager.deviceMotionActive) {
[_motionManager stopDeviceMotionUpdates];
_prevPoint = nil;
}
}
}
我们面临的问题是stopMotionUpdates崩溃,这也只是在iPad中崩溃。我们已经在具有不同操作系统版本的iPhone和iPad上进行了广泛的测试,我们只在iOS7和iOS8的iPad(迷你1,2和视网膜/非视网膜)上发生了故障。此外,我们无法在我们用于测试的所有iPad上重现崩溃,但只有少数。以下是main和崩溃线程的崩溃日志:
Thread : com.apple.main-thread
0 libsystem_kernel.dylib 0x00000001935f1cdc semaphore_wait_trap + 8
1 libdispatch.dylib 0x00000001934fbb3c _dispatch_semaphore_wait_slow + 252
2 CoreMotion 0x0000000186bf67d4 (null)
3 CoreMotion 0x0000000186be3698 (null)
4 MyApp 0x00000001002f7434 -[MyAppMotionManager stopMotionUpdates]
...
...
12 MyApp 0x00000001002e94f8 __getDispatchTimer_block_invoke
13 libdispatch.dylib 0x00000001934f3fd4 _dispatch_client_callout + 16
14 libdispatch.dylib 0x00000001934f5b90 _dispatch_source_invoke + 500
15 libdispatch.dylib 0x00000001934f7180 _dispatch_main_queue_callback_4CF + 244
16 CoreFoundation 0x00000001864fec2c __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 12
17 CoreFoundation 0x00000001864fcf6c __CFRunLoopRun + 1452
18 CoreFoundation 0x000000018643dc20 CFRunLoopRunSpecific + 452
19 GraphicsServices 0x000000018c0ddc0c GSEventRunModal + 168
20 UIKit 0x000000018956efdc UIApplicationMain + 1156
21 MyApp 0x00000001000c9850 main (main.m:14)
22 libdyld.dylib 0x000000019350faa0 start + 4
EXC_BREAKPOINT UNKNOWN at 0x0000000186c257ac
Thread : Crashed: Thread
0 CoreMotion 0x0000000186c257ac (null) + 110504
1 CoreMotion 0x0000000186c25774 (null) + 110448
2 CoreMotion 0x0000000186bf3c84 (null)
3 CoreMotion 0x0000000186bf67ec (null)
4 CoreMotion 0x0000000186bf3b80 (null)
5 CoreMotion 0x0000000186c24c48 (null) + 107588
6 CoreMotion 0x0000000186bf67ec (null)
7 CoreMotion 0x0000000186c24ba4 (null) + 107424
8 CoreMotion 0x0000000186be3b9c (null)
9 CoreMotion 0x0000000186bf6860 (null)
10 CoreFoundation 0x00000001864ff680 __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 20
11 CoreFoundation 0x00000001864fe838 __CFRunLoopDoBlocks + 300
12 CoreFoundation 0x00000001864fd0a4 __CFRunLoopRun + 1764
13 CoreFoundation 0x000000018643dc20 CFRunLoopRunSpecific + 452
14 CoreFoundation 0x00000001864932a8 CFRunLoopRun + 112
15 CoreMotion 0x0000000186bf653c (null)
16 libsystem_pthread.dylib 0x000000019368be1c _pthread_body + 168
17 libsystem_pthread.dylib 0x000000019368bd74 _pthread_body
由于我们在运动更新处理程序块中引用self,因此在刷新整个队列之前不应释放该对象。任何帮助表示赞赏:)
答案 0 :(得分:4)
您可能正在重载主线程。
根据经验,你不应该在主线程上做任何超过或大约一秒钟的事情。
主线程负责运行用户界面。如果您在任何大量时间内阻止主线程,则用户界面将无法接受无响应。
监视程序 - 为了保持用户界面的响应,iOS包含一个监视机制。如果您的应用程序未能及时响应某些用户界面事件(启动,暂停,恢复,终止)或某些操作在主线程上花费的时间稍多,那么看门狗将终止您的应用程序。看门狗给你的时间没有正式记录,但总是少一些。
任何此类操作都必须在后台线程上完成,您可以使用
轻松完成dispatch_async
NSOperationQueue
performSelectorInBackground
希望这有帮助。
答案 1 :(得分:2)
您的崩溃来自@synchronized
指令。如您所见,主线程正在@synchronized
中执行您的代码。这会锁定视图控制器,使其不被任何其他线程访问。
崩溃的线程是针对 CoreMotion 的,我想它正试图提供有关设备动作的更新。
我认为只有在某些情况下,当 CoreMotion 在主线程运行同步时尝试更新时,才会发生崩溃。
答案 2 :(得分:1)
你在哪里定义' operationQueue'没有自我,所以我假设它不是一个班级变量。您希望它是具有强引用的类属性,因此在接收更新时不会取消分配。我也看到过这种情况发生在蓝牙调用上的dispatch_queue_t的函数范围变量。
内存管理可以解释不稳定的行为,但你总是可以尝试通过打开其他应用程序来提高iOS的积极性。 iPad上你发现过这个问题的一堆网站标签。
CMMotion更新必须以FIFO顺序工作才能准确,这样才能解释为什么在日志中看到semaphore_wait_trap。