Optimización de CLLocationManager/CoreLocation para recuperar puntos de datos más rápido en el iPhone
corelocation ios (3)
Escribí un repositorio de GIT sobre esto, que puedes usar https://github.com/xelvenone/M6GPSLocationManager
- Si la precisión del resultado es mejor que la precisión aceptable, hemos terminado.
- Si recibimos una actualización sobre la ocurrencia, esperamos un máximo de WaitTimeForBetterResult para obtener una mejor, - Si esto no sucede, terminamos y tomamos la mejor
- Si recibimos actualizaciones constantemente, que superan los intentos máximos, tomamos la mejor (probablemente nos estamos moviendo)
- Si no obtenemos ninguna otra actualización en 30 segundos, habremos terminado (probablemente no habrá ninguna otra actualización)
Código
- (void)scopeToCurrentLocationWithAcceptableAccuracy:(CLLocationAccuracy)acceptableAccuracy
maximumWaitTimeForBetterResult:(NSTimeInterval)maximumWaitTimeForBetterResult
maximumAttempts:(NSInteger)maximumAttempts
onCompletion:(M6GPSLocationManagerCompletion)completion;
Actualmente estoy usando CoreLocation + CLLocationManager para comparar la ubicación actual de un usuario con la cantidad de N de otras ubicaciones. El problema al que me enfrento es que estoy tratando con áreas urbanas donde las ubicaciones están cerca unas de otras, por lo que necesito identificar la ubicación del usuario con la precisión que permite el dispositivo sin sacrificar demasiado tiempo. Mis cálculos son muy precisos, el problema es que lleva demasiado tiempo recopilar 10 muestras. Voy a pegar mis filtros / precisión del código respectivo a continuación. Si alguien puede comentar sobre cómo puedo acelerar esto, sería genial. Hasta que lo acelero, es bastante inútil en mi aplicación, ya que actualmente toma alrededor de 3-4 minutos recopilar información, una duración que no es aceptable para mi objetivo demográfico.
El código se ve algo como esto:
[self.locationManager setDistanceFilter:kCLDistanceFilterNone];
[self.locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
if (newLocation.horizontalAccuracy > 0.0f &&
newLocation.horizontalAccuracy < 120.0f) { // roughly an accuracy of 120 meters, we can adjust this.
[myLocs addObject:newLocation];
}
Gracias por cualquier truco de optimización para acelerar esto.
También he tenido muchos problemas con CLLocationManager en el iPhone. De diferentes aplicaciones, y de prueba y error, esto es lo que he descubierto;
1) Use una clase de singleton para el administrador de ubicaciones, SOLO UNA Instancia, siga los ejemplos en:
Ejemplo de LocateMe de Apple
Tweetero: http://tweetero.googlecode.com/svn/trunk
Pienso que solo puede tener un administrador de ubicación en funcionamiento, solo hay un chip GPS en el iPhone, por lo tanto, si inicia varios objetos del administrador de ubicación, tendrán problemas y obtendrá errores del administrador de ubicación de GPS indicando que no se puede actualizar. .
2) Tenga mucho cuidado al actualizar el locationManager.desiredAccuracy
y locationManager.distanceFilter
Siga el ejemplo en el código de Apple para esto en el FlipsideViewController:
[MyCLController sharedInstance].locationManager.desiredAccuracy = accuracyToSet;
[MyCLController sharedInstance].locationManager.distanceFilter = filterToSet;
Este enfoque funciona, y no causa errores. Si actualiza la exactitud deseada o distanceFilter en el ciclo de delegado principal:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
La ubicación central probablemente se quejará de que no puede actualizar los valores y le dará errores. Además, solo use las constantes para la desiredAccuracy
proporcionada por Apple, y ninguna otra, por lo tanto;
kCLLocationAccuracyBest, kCLLocationAccuracyNearestTenMeters,
kCLLocationAccuracyHundredMeters, kCLLocationAccuracyKilometer,
kCLLocationAccuracyThreeKilometers
El uso de otros valores puede darle errores desde locationManager. Para distanceFilter
puede usar cualquier valor, pero tenga en cuenta que la gente ha declarado que tiene problemas, el principal valor predeterminado es: -1 = Mejor, he usado 10.0 y parece que está bien.
3) Para forzar una nueva actualización, llame al método startUpdates
como en Tweetero, esto obliga a locationManager a hacer sus cosas, y debería intentar obtener un nuevo valor.
4) La rutina del delegado de ubicación central es difícil de obtener actualizaciones precisas. Cuando la aplicación se inicializa por primera vez, puede tener una precisión de 1000 metros o más, por lo que un intento no lo hará. Tres intentos después de la inicialización usualmente lo llevan a 47 o más metros, lo que es bueno. Recuerde que cada intento sucesivo llevará más y más tiempo para mejorar su precisión, por lo que se encarece rápidamente. Esto es lo que debe hacer: tomar un nuevo valor solo si es reciente Y si la nueva ubicación tiene una precisión ligeramente mayor tome la nueva ubicación O Si la nueva ubicación tiene una precisión <50 metros, tome la nueva ubicación O si el número de los intentos han 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 la 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 tiene un iPhone 3GS es mucho más fácil obtener actualizaciones de títulos, 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 a la gente!
didUpdateToLocation solo se actualiza cuando el usuario mueve la ubicación. Esto puede ser esporádico, como estoy seguro que ya notaste. CCLocationManager no envía actualizaciones regulares, sino que envía actualizaciones cuando el usuario se ha movido, o aumenta su precisión. Cuando estoy parado y comienzo una aplicación, generalmente recibo tres actualizaciones y luego nada por un tiempo. Google Maps hace un tipo de cosa similar, mostrando un punto vs anillo a medida que aumenta la precisión. Sugeriría esperar hasta que haya alcanzado la precisión requerida (<120.0f) y luego realizar su acción o cálculo.
Si estás acostumbrado a un GPS ''normal'', a donde se envían las actualizaciones y continúa mejorando su precisión, me temo que el iPhone no está diseñado para hacer esto.
De forma alternativa, puede utilizar la API de MapKit y mostrarle al usuario el mapa con su ubicación, y permitir que "acepte" una vez que sientan que la ubicación es lo suficientemente precisa. A veces me doy cuenta de que tengo un punto de referencia, y luego, 30 segundos después, me acerca unos 50 metros más cerca de donde realmente estoy.