У меня есть приложение, которое я недавно преобразовал в использование нового API компаса от Apple. Раньше использовались старые (теперь устаревшие) API.
Вот как я включаю обновления движения. Если службы определения местоположения недоступны, я должен запросить магнитный север, так как система не может определить магнитное склонение, чтобы определить север от магнитного севера. Если вы этого не сделаете, компас просто зависнет и ничего не произойдет.
if ( [CLLocationManager headingAvailable] )
{
if ( [CLLocationManager locationServicesEnabled] )
[motionMgr startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXTrueNorthZVertical];
else
[motionMgr startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXMagneticNorthZVertical];
}
Я вижу, что есть и другие случаи, когда истинный север не может быть получен. Если вы переведете устройство в авиарежим, оно не сможет найти склонение в Интернете и не сможет. Немного сложно заставить его выйти из строя таким образом, потому что иногда система кэширует старое магнитное склонение.
Кто-нибудь знает предпочтительный способ определить, может ли система получить истинный север? Я мог бы использовать класс Reachability, но это может быть излишним. Он все еще может определить истинный север из-за кэшированного значения.
[Редактировать]
Я нашел другой способ сделать это, который кажется несколько надежным. Похоже, что если вы запросите направление на истинный север, и он не сможет определить истинный север, то deviceMotion менеджера движения будет нулевым, когда вы его запросите. Вам нужно сделать это через секунду или две после его запуска, чтобы позволить диспетчеру движений начать работу.
[motionMgr startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXTrueNorthZVertical];
// Call checkForTrueNorth a second or so after starting motion updates to see if true north is available
// It needs a bit of time to get running. If it isn't available switch to using magnetic north.
[self performSelector:@selector(checkForTrueNorth) withObject:nil afterDelay:1.5];
- (void)checkForTrueNorth
{
if (motionMgr.deviceMotion == nil) // nil means it couldn't get true north.
{
[motionMgr stopDeviceMotionUpdates];
[motionMgr startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXMagneticNorthZVertical];
}
}
Меня беспокоит только этот метод: я не думаю, что в этом случае задокументировано поведение, возвращающее nil. Это работает сейчас, но, возможно, не в будущих версиях.