2009-07-04 11 views
17

Actualmente estoy usando CoreLocation + CLLocationManager para comparar la ubicación actual de un usuario a N cantidad de otras ubicaciones. El problema al que me enfrento es que estoy lidiando con áreas urbanas donde las ubicaciones están cerca unas de otras, por lo que debo señalar 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 recolectar 10 muestras. Pegaré mis filtros/código de precisión respectivo a continuación. Si alguien puede comentar sobre cómo puedo acelerar esto, sería genial. Hasta que lo acelere, 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 aceptada por mi objetivo demográfico.Optimización de CLLocationManager/CoreLocation para recuperar puntos de datos más rápido en el iPhone

Código 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 ningún tipo de trucos de optimización para acelerar este proceso.

Respuesta

48

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!

+0

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

+0

Me pregunto por qué marca "UseLocations" en los valores predeterminados del usuario? ¿Este valor es establecido automáticamente por el sistema operativo? – nonamelive

+1

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. –

4

didUpdateToLocation solo se actualiza cuando el usuario mueve la ubicación. Esto puede ser esporádico, como estoy seguro que has notado. CCLocationManager no envía actualizaciones periódicas, sino que envía actualizaciones cuando el usuario se ha mudado, o aumenta su precisión. Cuando estoy parado y empiezo una aplicación, suelo recibir aproximadamente tres actualizaciones, y luego nada durante un tiempo. Google Maps hace un tipo similar de cosas, mostrando un anillo vs punto a medida que aumenta la precisión. Sugeriría esperar hasta que hayas alcanzado la precisión requerida (< 120.0f) y luego realizar tu acción o cálculo.

Si está acostumbrado a un GPS "normal", donde se envían las actualizaciones y continúa perfeccionando su precisión, me temo que el iPhone no está diseñado para hacerlo.

Alternativamente, podría usar la API de MapKit, mostrar al usuario el mapa con su ubicación y permitir que 'acepten' una vez que sientan que la ubicación es lo suficientemente precisa. Noté que a veces obtengo un punto exacto, y luego, 30 segundos después, me mueve unos 50 metros más cerca de donde estoy en realidad.

0

me escribió un repositorio git en esto, que es libre de utilizar https://github.com/xelvenone/M6GPSLocationManager

  • Si la precisión resultado es mejor que acceptableAccuracy, hemos terminado
  • Si conseguimos una actualización de occuracy, esperamos maximumWaitTimeForBetterResult para obtener uno mejor, - Si esto no sucede, hemos terminado y tomamos el mejor
  • Si constantemente estamos obteniendo actualizaciones, que exceden los maximumAttempts, tomamos el mejor (probablemente nos mudemos de todos modos)
  • Si no obtenemos un Y otra actualización de 30 segundos, que se llevan a cabo (no habrá probablemente cualquier otra actualización)

Código

- (void)scopeToCurrentLocationWithAcceptableAccuracy:(CLLocationAccuracy)acceptableAccuracy 
       maximumWaitTimeForBetterResult:(NSTimeInterval)maximumWaitTimeForBetterResult 
          maximumAttempts:(NSInteger)maximumAttempts 
           onCompletion:(M6GPSLocationManagerCompletion)completion; 
Cuestiones relacionadas