I try use compass in my ios app. And I have one problem with it. If i implement
locationManagerShouldDisplayHeadingCalibration
method and return YES
in it, then calibration display is showing always. But I should make it like apple maps. I.e. calibration display should be showed sometimes. When compass should be calibration.
A much more straight-forward solution:
Objective-C
- (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager *)manager
{
CLLocationDirection accuracy = [[manager heading] headingAccuracy];
return accuracy <= 0.0f || accuracy > 10.0f;
}
This takes advantage of the fact that selectors performed on nil objects always return zero, and the fact the the accuracy is never going to be valid and equal to 0.0f (i.e. 100% accurate).
Swift
Due to the introduction of optionals, the simplest Swift solution does require branching and would look something like:
func locationManagerShouldDisplayHeadingCalibration(manager: CLLocationManager) -> Bool {
if let h = manager.heading {
return h.headingAccuracy < 0 || h.headingAccuracy > 10
}
return true
}
Note that we're looking at headingAccuracy
, for which Apple's docs state:
A positive value in this property represents the potential error between the value reported by the magneticHeading property and the actual direction of magnetic north. Thus, the lower the value of this property, the more accurate the heading. A negative value means that the reported heading is invalid, which can occur when the device is uncalibrated or there is strong interference from local magnetic fields.
OK I could not leave a comment so I thought I should leave a reply as Claude Houle's reply was useful to me.
I am using this improved version of Claude Houle's response.
- (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager *)manager{
if(!manager.heading) return YES; // Got nothing, We can assume we got to calibrate.
else if(manager.heading.headingAccuracy < 0 ) return YES; // 0 means invalid heading, need to calibrate
else if(manager.heading.headingAccuracy > 5 ) return YES; // 5 degrees is a small value correct for my needs, too.
else return NO; // All is good. Compass is precise enough.
}
Also wanted to say what Claude Houle says almost implements the API docs here which states:
If you return NO from this method or do not provide an implementation for it in your delegate, Core Location does not display the heading calibration alert. Even if the alert is not displayed, calibration can still occur naturally when any interfering magnetic fields move away from the device. However, if the device is unable to calibrate itself for any reason, the value in the headingAccuracy property of any subsequent events will reflect the uncalibrated readings.
manager.heading is CLHeading. that is why manager.heading > 5 will give a warning. self.currentHeading.headingAccuracy > 5 is the true one.
I use the following code:
@property (nonatomic, retain) CLHeading * currentHeading; // Value updated by @selector(locationManager:didUpdateHeading:)
...
...
- (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager *)manager{
if( !self.currentHeading ) return YES; // Got nothing, We can assume we got to calibrate.
else if( self.currentHeading.headingAccuracy < 0 ) return YES; // 0 means invalid heading. we probably need to calibrate
else if( self.currentHeading.headingAccuracy > 5 )return YES; // 5 degrees is a small value correct for my needs. Tweak yours according to your needs.
else return NO; // All is good. Compass is precise enough.
}
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