We have an instance of CMMotionManager in our app which we use to get sensor updates at a frequency of 5Hz. Following is the code we use to start motion updates:
[self.motionManager
startDeviceMotionUpdatesUsingReferenceFrame:
CMAttitudeReferenceFrameXMagneticNorthZVertical
toQueue:operationQueue
withHandler:^(CMDeviceMotion *motion, NSError *error) {
if (!error) {
[self doSomethingWithMotion:motion];
} else { ... }
The above method is always invoked on the main thread.
Now, once we are done with our task, we stop motion updates by calling the following method, again on the main thread :
- (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;
}
}
}
The issue we are facing is that the stopMotionUpdates crashes, that too, only in iPads. We have tested this extensively on iPhones and iPads with different OS versions and we get the crash only on iPads (mini 1,2 and retina/non-retina) for both iOS7 and iOS8. Also, we cannot reproduce the crash on all iPads which we use for testing, but only a few. Following are the crash logs for main and the crashed thread:
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
Since we reference self in the motion update handler block, the object shouldn't be deallocated till the entire queue is flushed. Any help is appreciated :)
You might be overloading the main thread.
As a rule of thumb, you should never do anything on the main thread that takes more than or about a second.
The main thread is responsible for running the user interface. If you block the main thread for any significant amount of time, the user interface becomes unacceptably unresponsive.
watchdog — In order to keep the user interface responsive, iOS includes a watchdog mechanism. If your application fails to respond to certain user interface events (launch, suspend, resume, terminate) in time or some operation takes little bit more time on the main thread then the watchdog will kill your application. The amount of time the watchdog gives you is not formally documented, but it's always less.
Any such operation must be done on a background thread and you could easily do it using
dispatch_async
NSOperationQueue
performSelectorInBackground
Hope this helps.
Your crash comes from the @synchronized
directive. As you can see the main thread is executing your code in @synchronized
. This locks the view controller, from being accessed by any other thread.
The thread that is crashed is for the CoreMotion and I suppose it was trying to give updates on the device motion.
I believe the crash is happening just in some cases when the CoreMotion happens to try to updates in the same time your main thread runs through synchronized.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With