2014-01-29 3 views
6

У меня странная проблема с обновлением местоположения пользователя. Иногда мое приложение обновляет местоположение, но время от времени прерывает обновление. Я не знаю, где проблема, мой код (от AppDelegate.m) ниже:ios, startMonitoringSignificantLocationChanges - иногда прерывает мониторинг

- (void)applicationDidEnterBackground:(UIApplication *)application 
{ 
    NSLog(@"Went to Background"); 
    // Only monitor significant changes 
    [locationManager startMonitoringSignificantLocationChanges]; 
} 


- (void)applicationDidBecomeActive:(UIApplication *)application 
{ 
    // Start location services 
    locationManager = [[CLLocationManager alloc] init]; 
    locationManager.desiredAccuracy = kCLLocationAccuracyBest; 

    // Only report to location manager if the user has traveled 1000 meters 
    locationManager.distanceFilter = 1000.0f; 
    locationManager.delegate = self; 
    locationManager.activityType = CLActivityTypeAutomotiveNavigation; 

    [locationManager stopMonitoringSignificantLocationChanges]; 
    [locationManager startUpdatingLocation]; 
} 


- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations 
{ 
    // Check if running in background or not 
    BOOL isInBackground = NO; 
    if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) { 
     isInBackground = YES; 
    } 

    if (isInBackground) { 
     // If we're running in the background, run sendBackgroundLocationToServer 
     [self sendBackgroundLocationToServer:[locations lastObject]]; 
    } else { 
     // If we're not in the background wait till the GPS is accurate to send it to the server 
     if ([[locations lastObject] horizontalAccuracy] < 100.0f) { 
      [self sendDataToServer:[locations lastObject]]; 
     } 
    } 
} 


-(void) sendBackgroundLocationToServer:(CLLocation *)location 
{ 
    bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ 
     [[UIApplication sharedApplication] endBackgroundTask:bgTask]; 
    }]; 

    // Send the data 
    [self sendDataToServer:location]; 

    if (bgTask != UIBackgroundTaskInvalid) { 
     [[UIApplication sharedApplication] endBackgroundTask:bgTask]; 
     bgTask = UIBackgroundTaskInvalid; 
    } 
} 

-(void) sendDataToServer:(CLLocation *)newLocation 
{ 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 

     NSString *lat = [NSString stringWithFormat:@"%.8f", newLocation.coordinate.latitude]; 
     NSString *lng = [NSString stringWithFormat:@"%.8f", newLocation.coordinate.longitude]; 

     [APIConnection SaveMyPositionWitLat:lat withLng:lng]; 

    }); 
} 

мне нужно обновить местоположение каждый час или, если пользователь изменит расположение более 1000 м. Я выбрал второй способ, чтобы сэкономить аккумулятор, но мое решение не работает, как мне нужно.

Я был бы очень признателен за любую помощь в этом, спасибо заранее!

ответ

31

Я не могу сказать наверняка, если это вы все проблемы, но я хотел бы сделать следующие изменения:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{ 
    // Moved to didFinishLaunching... you should not be recreating every time app 
    // becomes active. You can check for locations key in the options Dictionary if 
    // it is necessary to alter your setup based on background launch 

    // Start location services 
    locationManager = [[CLLocationManager alloc] init]; 
    locationManager.desiredAccuracy = kCLLocationAccuracyBest; 

    // Only report to location manager if the user has traveled 1000 meters 
    locationManager.distanceFilter = 1000.0f; 
    locationManager.delegate = self; 
    locationManager.activityType = CLActivityTypeAutomotiveNavigation; 

    // Start monitoring significant locations here as default, will switch to 
    // update locations on enter foreground 
    [locationManager startMonitoringSignificantLocationChanges]; 

    // Hold in property to maintain reference 
    self.locationManager = locationManager; 
} 

После вашего свинца, это было бы все, что остается в вашем методе didBecomeActive (я бы использовать willEnterForeground вместо этого):

- (void)willEnterForeground:(UIApplication *)application 
{ 
    [self.locationManager stopMonitoringSignificantLocationChanges]; 
    [self.locationManager startUpdatingLocation]; 
} 

Ввод в фоновом режиме, вернитесь только значительные изменения местоположения:

- (void)applicationDidEnterBackground:(UIApplication *)application 
{ 
    NSLog(@"Went to Background"); 
    // Need to stop regular updates first 
    [self.locationManager stopUpdatingLocation]; 
    // Only monitor significant changes 
    [self.locationManager startMonitoringSignificantLocationChanges]; 
} 

В методе делегата я рекомендую вынуть все условные фоновые тесты. Я обертываю идентификатор фоновой задачи в случае, если приложение находится в фоновом режиме или идет в фоновый режим перед завершением. Я также реагирование на глобальном потоке, поэтому мы не блокировать пользовательский интерфейс (опционально):

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations 
{ 

    UIApplication *app = [UIApplication sharedApplication]; 
    __block UIBackgroundTaskIdentifier locationUpdateTaskID = [app beginBackgroundTaskWithExpirationHandler:^{ 
     dispatch_async(dispatch_get_main_queue(), ^{ 
      if (locationUpdateTaskID != UIBackgroundTaskInvalid) { 
       [app endBackgroundTask:locationUpdateTaskID]; 
       locationUpdateTaskID = UIBackgroundTaskInvalid; 
      } 
     }); 
    }]; 

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 

     // You might consider what to do here if you do not ever get a location accurate enough to pass the test. 
     // Also consider comparing to previous report and verifying that it is indeed beyond your threshold distance and/or recency. You cannot count on the LM not to repeat. 
     if ([[locations lastObject] horizontalAccuracy] < 100.0f) { 
      [self sendDataToServer:[locations lastObject]]; 
     } 

     // Close out task Identifier on main queue 
     dispatch_async(dispatch_get_main_queue(), ^{ 
      if (locationUpdateTaskID != UIBackgroundTaskInvalid) { 
       [app endBackgroundTask:locationUpdateTaskID]; 
       locationUpdateTaskID = UIBackgroundTaskInvalid; 
      } 
     }); 
    }); 
} 

Посмотреть мой проект, TTLocationHandler

на Github еще несколько примеров использования Core Location пути, который вы хотите использовать Это.

+0

Thx, это решает мою проблему, но что я должен изменить свой код для получения места каждый час? – Nizzre

+0

Вы могли бы подумать, что для этого потребуется фоновый режим и установка таймера, который вполне возможен, но я не уверен, что Apple одобрит его. В интересах экономии ваших пользователей от безумного использования батареи, я снова предлагаю вам взглянуть на это немного по-другому. Если у вас есть существенные изменения в концепции и мониторинге региона, вы можете сохранить разумное представление о местоположении устройства. Если они не двигались, нет смысла постоянно проверять. В любом случае это другой вопрос, для которого у меня есть некоторые соображения. –

+2

отличная работа здесь @DeanDavids. просто просмотрел вашу библиотеку! – wprater

Смежные вопросы