También he tenido muchos problemas con CLLocationManager en el iPhone. De diferentes aplicaciones, y prueba y error esto es lo que he descubierto;
1) Utilizar una clase singleton para la locationManager, sólo una instancia, seguir los ejemplos en: ejemplo
LocateMe de Apple
Tweetero: http://tweetero.googlecode.com/svn/trunk
estoy pensando que sólo puede tener uno gestor de ubicación en ejecución, solo hay un chip GPS en el iPhone, por lo tanto, si lanza varios objetos del administrador de ubicación, entrarán en conflicto y obtendrá errores del administrador de ubicación del GPS que indique que no se puede actualizar.
2) Tenga mucho cuidado de cómo actualizar el locationManager.desiredAccuracy
y locationManager.distanceFilter
seguir el ejemplo de código de Apple para esto en el FlipsideViewController:
[MyCLController sharedInstance].locationManager.desiredAccuracy = accuracyToSet;
[MyCLController sharedInstance].locationManager.distanceFilter = filterToSet;
Este enfoque funciona, y no provoca errores.Si actualiza el desiredAccuracy o distanceFilter en el bucle principal delegado:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
Core Location probable que se quejan de que no se puede actualizar los valores, y le dará errores. Además, solo use las constantes para el desiredAccuracy
suministradas por Apple, y ninguna otra, ;
kCLLocationAccuracyBest, kCLLocationAccuracyNearestTenMeters,
kCLLocationAccuracyHundredMeters, kCLLocationAccuracyKilometer,
kCLLocationAccuracyThreeKilometers
El uso de otros valores que puede dar errores de locationManager. Para distanceFilter
puede usar cualquier valor, pero tenga en cuenta que la gente ha declarado que tiene problemas, el valor principal predeterminado es: -1 = Mejor, he usado 10.0 y parece correcto.
3) Para forzar una nueva actualización, llame al método startUpdates
como en Tweetero, esto fuerza a locationManager a hacerlo, y debería intentar obtener un nuevo valor.
4) La rutina de delegado de ubicación central es difícil de obtener actualizaciones precisas. Cuando su aplicación se inicializa por primera vez, puede tener una precisión de 1000 metros o más, por lo tanto un intento no lo va a hacer. Tres intentos después de la inicialización generalmente le dan dentro de 47 o más metros, lo que es bueno. Recuerde que cada intento sucesivo está yendo para tomar más y más tiempo para mejorar su precisión, por lo que se vuelve costoso rápidamente. Esto es lo que necesita hacer: Tome un nuevo valor solo si es reciente Y Si la nueva ubicación tiene una precisión ligeramente mejor tome la nueva ubicación O Si la nueva ubicación tiene una precisión de < 50 metros tome la nueva ubicación O Si el número de intentos ha excedido 3 o 5 Y la precisión < 150 metros Y la ubicación ha CAMBIADO, entonces esta es una nueva ubicación y el dispositivo se movió así que tome este valor incluso si su precisión es peor. Aquí está mi código de ubicación para hacer esto:
- (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's 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's 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];
}
Si tienes un iPhone 3GS obtener actualizaciones de rumbo es mucho más fácil, aquí está el código en el mismo módulo que el anterior:
//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];
}
}
Espero que esto ayude ¡gente!
Gran código. Pero como se indica en la respuesta a continuación, didUpdateToLocation puede tardar mucho tiempo en activarse. Lo intenté y lo intenté y, a pesar de ello, estoy viendo actualizaciones bastante lentas cuando estoy dentro, algunas veces me lleva un minuto o más. Sin embargo, si cambio a Maps.app, encuentra mi ubicación al instante. Me gustaría poder obtener la misma precisión instantánea a través de la API que con MapKit. – runmad
Me pregunto por qué marca "UseLocations" en los valores predeterminados del usuario? ¿Este valor es establecido automáticamente por el sistema operativo? – nonamelive
Gran código. Cuando configura locationChanged = YES, la instrucción if debería usar || en lugar de &&. Si el lat o lon ha cambiado, la ubicación ha cambiado. –