2013-10-24 2 views
6

В моем корневом контроллере У меня есть свойство с CMMotionManagerя OSSpinLockLock при вызове startDeviceMotionUpdatesToQueue внутри контроллера

@property (strong, nonatomic) CMMotionManager *MManager; 

В своем добытчике я ленивая экземпляра. Когда вид нагрузки контроллера, я называю этот метод

- (void)reloadAccelerometer { 
    NSLog(@"Away we go"); 
    self.MManager.deviceMotionUpdateInterval = 10.0/60.0; 
    [self.MManager startDeviceMotionUpdatesToQueue:self.queue withHandler:^(CMDeviceMotion *motion, NSError *error) { 
     NSLog(@"Y values is: %f", motion.userAcceleration.y); 
    }]; 
} 

Я вижу «понеслось» в NSLog, а затем сразу же приложение падает, и я получаю эту тему журнал

libsystem_platform.dylib`spin_lock$VARIANT$mp: 
0x39a87814: movs r1, #1 

libsystem_platform.dylib`OSSpinLockLock$VARIANT$mp + 2: 
0x39a87816: ldrex r2, [r0] 
0x39a8781a: cmp r2, #0 
0x39a8781c: it  ne 
0x39a8781e: bne.w 0x39a893ec    ; _OSSpinLockLockSlow$shim 
0x39a87822: strex r2, r1, [r0] 
0x39a87826: cmp r2, #0 
0x39a87828: bne 0x39a87816    ; OSSpinLockLock$VARIANT$mp + 2 
0x39a8782a: dmb ish 
0x39a8782e: bx  lr 

Что моя ошибка? Я разместил reloadAccelerometer не в том месте?

ответ

6

Я пытался сделать что-то подобное в своем приложении iOS и провел forever, пытаясь понять, в чем причина аварии. Это было очень загадочное (и надоедливое) исключение. В конце концов я понял это после прочтения отчетов о сбоях, что OSSpinLock связано с проблемой управления потоком/очередью.

NSOperationQueue является преступником здесь. Ваш код не отображается, как вы создавали ваши NSOperationQueue, но я предполагаю, что это было что-то вроде этого:

NSOperationQueue *aQueue = [[NSOperationQueue alloc] init]; // Do NOT do this 
[self.MManager startDeviceMotionUpdatesToQueue:aQueue withHandler:^(CMDeviceMotion *motion, NSError *error) { 
    NSLog(@"Y values is: %f", motion.userAcceleration.y); 
}]; 

Оказывается, что это не способ использовать NSOperationQueue. Этот объект aQueue является причиной аварии.

Чтобы правильно настроить очередь операций и избежать сбоя, переместите CMMotionManager в другой поток. Затем сообщите NSOperationQueue об использовании currentQueue, а не mainQueue. Apple рекомендует, чтобы он не запускался на mainQueue, однако, если ваше приложение в настоящее время работает в основной очереди, то я не вижу, как currentQueue отличается от других. Я попытался переместить код ниже в другую очередь, используя GCD, но никакого кода никогда не вызывали.

Вот что ваш окончательный код должен выглядеть следующим образом:

// Check if Motion/Location services are available 
if (motionManager.deviceMotionAvailable == YES && motionManager.accelerometerAvailable == YES) { 
    NSLog(@"Away we go"); 
    self.MManager.deviceMotionUpdateInterval = 10.0/60.0; 
    [self.MManager startDeviceMotionUpdatesToQueue:[NSOperationQueue currentQueue] withHandler:^(CMDeviceMotion *motion, NSError *error) { 
     NSLog(@"Y values is: %f", motion.userAcceleration.y); 
    }]; 
} else { 
    // Motion/Accelerometer services unavailable 
} 

Я хотел бы также отметить, что ваше творение собственности CMMotionManager (к моему знанию) правильно с (strong, nonatomic).

+1

Ничего себе, блестящий ответ! Спасибо RazorSharp :) –

Смежные вопросы