Ответ 1
У меня было много проблем с CLLocationManager на iPhone. Из разных приложений и проб и ошибок это то, что я выяснил;
1) Используйте класс singleton для locationManager, ТОЛЬКО один экземпляр, следуйте примерам в:
Пример Apple LocateMe
Tweetero: http://tweetero.googlecode.com/svn/trunk
Я думаю, что у вас может быть только один менеджер местоположений, есть только один GPS-чип в iPhone, поэтому, если вы запустите несколько объектов менеджера местоположений, они будут конфликтовать, и вы получите ошибки от менеджера местоположения GPS, заявив, что он может 't update.
2) Будьте предельно осторожны, как вы обновляете locationManager.desiredAccuracy
и locationManager.distanceFilter
Следуйте примеру кода Apple для этого в FlipsideViewController:
[MyCLController sharedInstance].locationManager.desiredAccuracy = accuracyToSet;
[MyCLController sharedInstance].locationManager.distanceFilter = filterToSet;
Этот подход работает и не вызывает ошибок. Если вы обновите желаемую функцию или distanceFilter в основной цепочке делегатов:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
Основное местоположение, скорее всего, будет жаловаться на то, что оно не сможет обновить значения и дать вам ошибки. Кроме того, используйте только константы для desiredAccuracy
, поставляемые Apple, и другие, Таким образом,
kCLLocationAccuracyBest, kCLLocationAccuracyNearestTenMeters,
kCLLocationAccuracyHundredMeters, kCLLocationAccuracyKilometer,
kCLLocationAccuracyThreeKilometers
Использование других значений может привести к ошибкам в locationManager. Для distanceFilter
вы можете использовать любое значение, но знайте, что люди заявили, что у него есть проблемы, главное значение по умолчанию: -1 = Наилучшее, я использовал 10.0 и кажется ОК.
3) Чтобы заставить новое обновление вызвать метод startUpdates
, как в Tweetero, это заставляет
locationManager, чтобы сделать это, и он должен попробовать и получить новое значение.
4) Основная функция делегирования местоположения сложна для получения точных обновлений. Когда ваше приложение сначала инициализируется, вы можете быть в точности на 1000 метров и более, таким образом одна попытка не собирается этого делать. Обычно три попытки после инициализации до 47 метров, что хорошо. Помните, что каждая последующая попытка для того, чтобы повысить вашу точность, и поэтому она становится дорогой быстро. Это то, что вам нужно сделать: Возьмите новое значение только в том случае, если оно является недавним И Если новое местоположение имеет немного лучшую точность, возьмите новое местоположение ИЛИ Если новое местоположение имеет точность < 50 метров берут новое место ИЛИ Если количество попыток превысило 3 или 5 и точность < 150 метров И местоположение было изменено, то это новое место, и устройство перемещено, поэтому сделайте это даже если точность хуже. Здесь мой код места для этого:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
locationDenied = NO;
if(![[NSUserDefaults standardUserDefaults] boolForKey:@"UseLocations"])
{
[self stopAllUpdates];
return;
}
NSDate* eventDate = newLocation.timestamp;
NSTimeInterval howRecent = abs([eventDate timeIntervalSinceNow]);
attempts++;
if((newLocation.coordinate.latitude != oldLocation.coordinate.latitude) && (newLocation.coordinate.longitude != oldLocation.coordinate.longitude))
locationChanged = YES;
else
locationChanged = NO;
#ifdef __i386__
//Do this for the simulator since location always returns Cupertino
if (howRecent < 5.0)
#else
// Here the theory of operation
// If the value is recent AND
// If the new location has slightly better accuracy take the new location OR
// If the new location has an accuracy < 50 meters take the new location OR
// If the attempts is maxed (3 -5) AND the accuracy < 150 AND the location has changed, then this must be a new location and the device moved
// so take this new value even though it accuracy might be worse
if ((howRecent < 5.0) && ( (newLocation.horizontalAccuracy < (oldLocation.horizontalAccuracy - 10.0)) || (newLocation.horizontalAccuracy < 50.0)
|| ((attempts >= attempt) && (newLocation.horizontalAccuracy <= 150.0) && locationChanged)))
#endif
{
attempts = 0;
latitude = newLocation.coordinate.latitude;
longitude = newLocation.coordinate.longitude;
[currentLocation release];
currentLocation = [newLocation retain];
goodLocation = YES;
[[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateLocationNotification" object: nil];
if (oldLocation != nil) {
distanceMoved = [newLocation getDistanceFrom:oldLocation];
currentSpeed = newLocation.speed;
distanceTimeDelta = [newLocation.timestamp timeIntervalSinceDate:oldLocation.timestamp];
}
}
// Send the update to our delegate
[self.delegate newLocationUpdate:currentLocation];
}
Если у вас есть iPhone 3GS, получение обновлений заголовков намного проще, вот код в том же модуле, что и выше:
//This is the Heading or Compass values
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading {
if (newHeading.headingAccuracy > 0)
{
[newHeading retain];
// headingType = YES for True North or NO for Magnetic North
if(headingType) {
currentHeading = newHeading.trueHeading;
} else {
currentHeading = newHeading.magneticHeading;
}
goodHeading = YES;
[[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateHeadingNotification" object: nil];
}
}
Надеюсь, это поможет людям!