2009-07-04 6 views
17

Actuellement, j'utilise CoreLocation + CLLocationManager afin de comparer l'emplacement actuel d'un utilisateur à N nombre d'autres emplacements. Le problème auquel je suis confronté est que je suis confronté à des zones urbaines où les emplacements sont proches les uns des autres, je dois donc préciser l'emplacement de l'utilisateur aussi précisément que l'appareil le permet sans sacrifier trop de temps. Mes calculs sont précis, le problème est qu'il faut beaucoup trop de temps pour collecter 10 échantillons. Je vais coller mes filtres/code respectif de précision ci-dessous. Si quelqu'un peut commenter sur la façon dont je peux accélérer cela, ce serait génial. Jusqu'à ce que je l'accélère, il est plutôt inutile dans mon application car cela prend actuellement environ 3-4 minutes pour recueillir des informations, une durée qui n'est pas acceptée par mon groupe démographique cible.Optimisation de CLLocationManager/CoreLocation pour récupérer des points de données plus rapidement sur l'iPhone

code ressemble à ceci:

[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]; 
} 

Merci pour toute astuces d'optimisation pour accélérer ce. DidUpdateToLocation ne se met à jour que lorsque l'utilisateur déplace sa position.

Répondre

48

J'ai eu beaucoup de problèmes avec CLLocationManager sur l'iPhone aussi. De différentes applications, et des essais et erreurs, c'est ce que j'ai compris;

1) Utilisez une classe singleton pour le LocationManager, une seule instance, suivre les exemples:

exemple Apple LocateMe

Tweetero: http://tweetero.googlecode.com/svn/trunk

Je pense que vous ne pouvez avoir qu'un Le gestionnaire de localisation fonctionne, il n'y a qu'une seule puce GPS dans l'iPhone, donc si vous lancez plusieurs objets du gestionnaire de position, ils entreront en conflit, et vous obtiendrez des erreurs du gestionnaire de localisation GPS indiquant qu'il ne peut pas mettre à jour.

2) Soyez extrêmement prudent lorsque vous mettez à jour le locationManager.desiredAccuracy et locationManager.distanceFilter

Suivez l'exemple dans le code d'Apple pour cela dans le FlipsideViewController:

[MyCLController sharedInstance].locationManager.desiredAccuracy = accuracyToSet; 
[MyCLController sharedInstance].locationManager.distanceFilter = filterToSet; 

Cette approche fonctionne et ne provoque pas d'erreurs.Si vous mettez à jour le desiredAccuracy ou distanceFilter dans la boucle principale délégué:

- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation 

Lieu Core se plaindra probablement qu'il ne peut pas mettre à jour les valeurs, et vous donner des erreurs. En outre, utilisez uniquement les constantes pour le desiredAccuracy fourni par Apple, et pas d'autres, ainsi;

kCLLocationAccuracyBest, kCLLocationAccuracyNearestTenMeters,
kCLLocationAccuracyHundredMeters, kCLLocationAccuracyKilometer,
kCLLocationAccuracyThreeKilometers

L'utilisation d'autres valeurs peut vous donner des erreurs de LocationManager. Pour distanceFilter vous pouvez utiliser n'importe quelle valeur, mais sachez que les gens ont déclaré avoir des problèmes, la valeur par défaut est: -1 = Meilleur, j'ai utilisé 10.0 et il semble OK.

3) Pour forcer une nouvelle mise à jour, appelez la méthode startUpdates comme dans Tweetero, cela force locationManager à le faire, et il devrait essayer de vous donner une nouvelle valeur.

4) La routine de délégation de l'emplacement de base est délicate pour obtenir des mises à jour précises. Lorsque votre application initialise d'abord vous pouvez être hors de précision de 1000 mètres ou plus, donc une tentative ne va pas le faire. Trois tentatives après l'initialisation vous donne généralement à 47 mètres ou plus, ce qui est bon. Rappelez-vous que chaque tentative successive prend pour prendre de plus en plus de temps pour améliorer votre précision, et qu'elle devient rapidement chère. C'est ce que vous devez faire: Prendre une nouvelle valeur seulement si elle est récente ET Si le nouvel emplacement a une précision légèrement meilleure prendre le nouvel emplacement OU Si le nouvel emplacement a une précision < 50 mètres prendre le nouvel emplacement OU Si le nombre de tentatives a dépassé 3 ou 5 ET la précision < 150 mètres ET l'emplacement a CHANGÉ, alors ceci est un nouvel emplacement et le dispositif déplacé alors prenez cette valeur même si sa précision est pire. Voici mon code d'emplacement pour ce faire:

- (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 vous avez un iPhone 3GS obtenir Heading des mises à jour est beaucoup plus facile, voici le code dans le même module que ci-dessus:

//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]; 

    } 
} 

Hope this helps gens!

+0

code Grand. Mais comme les notes de réponse ci-dessous, il peut prendre beaucoup de temps pour didUpdateToLocation: à feu. J'ai essayé et essayé et peu importe, je vois des mises à jour plutôt lentes quand je suis à l'intérieur - parfois cela prend une minute ou plus. Cependant, si je passe à Maps.app, il trouve instantanément ma position. Je souhaite que nous puissions obtenir la même précision instantanée à travers l'API qu'avec MapKit. – runmad

+0

Je me demande pourquoi il vérifie "UseLocations" dans les valeurs par défaut de l'utilisateur? Cette valeur est-elle définie automatiquement par le système d'exploitation? – nonamelive

+1

Bon code. Lorsque vous définissez locationChanged = YES, l'instruction if doit utiliser || au lieu de &&. Si le lat ou le lon a changé, l'emplacement a changé. –

4

Cela peut être sporadique, comme je suis sûr que vous avez remarqué. CCLocationManager n'envoie pas de mises à jour régulières, mais envoie des mises à jour lorsque l'utilisateur a déménagé, ou augmente la précision. Lorsque je suis stationnaire et que je démarre une application, je reçois généralement trois mises à jour, puis rien pendant un moment. Google Maps fait une sorte de chose similaire, montrant un anneau vs point que la précision augmente. Je vous suggère d'attendre que vous ayez atteint la précision requise (< 120.0f), puis d'effectuer votre action ou votre calcul.

Si vous êtes habitué à un GPS "normal", où les mises à jour sont envoyées, et il continue à affiner sa précision, je crains que l'iPhone n'est pas conçu pour le faire.

Alternativement, vous pouvez utiliser l'API MapKit et montrer à l'utilisateur la carte avec son emplacement, et lui permettre de «accepter» une fois qu'il a l'impression que l'emplacement est suffisamment précis. Je remarque parfois que je reçois un point, et 30 secondes plus tard, cela me rapproche peut-être de 50 mètres de l'endroit où je suis réellement.

0

J'ai écrit un git sur ce point, que vous êtes libre d'utiliser https://github.com/xelvenone/M6GPSLocationManager

  • Si la précision du résultat est meilleur que acceptableAccuracy, nous fait
  • Si nous obtenons une mise à jour sur occuracy, nous attendons maximumWaitTimeForBetterResult pour obtenir un meilleur, - Si cela n'arrive pas, nous avons fini et prendre le meilleur
  • Si nous recevons constamment des mises à jour, qui dépassent les attentes maximales, nous prenons le meilleur (probablement nous déménageons de toute façon)
  • Si nous ne recevons pas de y autre mise à jour en 30 sec, nous fait (il n'y aura pas probablement une autre mise à jour)

code

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