2012-09-10 12 views
7

Si la aplicación se está ejecutando y la clase CLLocationManagerDelegate es el primer plano (es decir, visible), entonces didEnterRegions se activa y obtengo tanto el NSLog como el AlertView. Sin embargo, no obtengo nada cuando la aplicación está en segundo plano o, esencialmente, si la pantalla muestra algo más que la clase de delegado.didEnterRegion funciona en primer plano pero no en fondo u otros VCs

He configurado "Registros de aplicación para actualizaciones de ubicación" en "Modos de fondo requeridos" en la lista, aunque no estoy seguro de que sea necesario.

Esto es lo que creo que es el código relevante, aunque puedo estar equivocado (y con mucho gusto añadiré más). Debo señalar que todo en viewDidLoad está envuelto en un if que comprueba si la monitorización de región está disponible y habilitada.

- (void)viewDidLoad 
{ 
    NSLog(@"MapViewController - viewDidLoad"); 
    self.locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters; 
    self.locationManager.distanceFilter = kCLLocationAccuracyNearestTenMeters;  
    self.locationManager.delegate = self; 
    [self.locationManager startMonitoringSignificantLocationChanges]; 
} 

- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region 
{ 
    NSLog(@"MapViewController - didEnterRegion"); 
    NSLog(@"MVC - didEnterRegion - region.radius = %f", region.radius); 
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"entered region..." message:@"You have Entered the Location." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil]; 
    alert.tag = 2; 
    [alert show]; 
} 

aquí es donde consigo la lista de regiones está supervisando, en AppDelegate.m:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{ 

// other code 

NSLog(@"LISTING ALL REGIONS MONITORED"); 
    NSArray *regions = [self.locationManager.monitoredRegions allObjects]; 
    if (!regions) { 
     NSLog(@"no regions found"); 
    } else { 
     NSLog(@"got %d monitored regions", [regions count]); 
     for (int i = 0; i < [regions count]; i++) { 
      CLRegion *region = [regions objectAtIndex:i]; 
      NSLog(@"region %d's identifier = %@", i, region.identifier); 
      NSLog(@"region: radius: %@", region.radius); 
     } 
    } 

// other code 
} 

me llaman startMonitoringForRegion dos veces, aquí es el lugar principal:

- (void)doneButtonTapped { 
    NSLog(@"doneButtonTapped"); 

    if (self.locationIdentifier) { 
     if ([CLLocationManager regionMonitoringEnabled] && [CLLocationManager regionMonitoringAvailable]) { 

      // core data setup 
      NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
      NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"LocationReminder" inManagedObjectContext:self.managedObjectContext]; 
      fetchRequest.entity = entityDescription; 
      NSPredicate *predicate = [NSPredicate predicateWithFormat:@"locationIdentifier == %@", self.locationIdentifier]; 
      fetchRequest.predicate = predicate; 
      NSError *error; 
      NSArray *results = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error]; 
      if (results) { 

       // get the LocationReminder 
       LocationReminder *retrievedReminder = [results objectAtIndex:0]; 
       retrievedReminder.audioURI = [[[self.audioPlayers objectAtIndex:self.selectedCell] url] absoluteString]; 
       retrievedReminder.userRecording = nil; 

       // start monitoring it's region 
       NSArray *coordinateArray = [retrievedReminder.locationIdentifier componentsSeparatedByString:@", "]; 
       CLLocationCoordinate2D coordinate = {[[coordinateArray objectAtIndex:0] doubleValue], [[coordinateArray objectAtIndex:1] doubleValue]}; 
       CLRegion *newRegion = [[CLRegion alloc] initCircularRegionWithCenter:coordinate radius:250.0 identifier:retrievedReminder.locationIdentifier]; 
       NSLog(@"about to monitor region with radius: %f", newRegion.radius); 
       [self.locationManager startMonitoringForRegion:newRegion desiredAccuracy:kCLLocationAccuracyBest]; 

       // save the LocationReminder 
       if (![self.managedObjectContext save:&error]) { 
        NSLog(@"hmm. no managed object context. must be something space-time going on"); 
       } else { 
        NSLog(@"saved locationReminder, locationIdentifier = %@", retrievedReminder.locationIdentifier); 
       } 
      } else { 
       NSLog(@"ERROR: no LocationReminder retreived for predicate: %@", predicate); 
      } 
     } 

     // get the mapview controller off of the navigation stack 
     for (UIViewController *viewController in self.navigationController.viewControllers) { 
      if ([viewController isKindOfClass:[MapViewController class]]) { 
       MapViewController *mapVC = (MapViewController *)viewController; 
       mapVC.audioURI = [[[self.audioPlayers objectAtIndex:self.selectedCell] url] absoluteString]; 
       [self.navigationController popToViewController:mapVC animated:YES]; 
      } 
     } 
} 

Y porque Tengo la sensación de que podría ser importante, aquí está el getter para locationManager:

- (CLLocationManager *)locationManager { 
    NSLog(@"MapViewController - locationManager"); 
    if (_locationManager) { 
     return _locationManager; 
    } else { 
     _locationManager = [[CLLocationManager alloc] init]; 
     return _locationManager; 
    } 
} 

ACTUALIZACIÓN 1: A través de los foros de Apple (donde hice una cruz) alguien mencionó que AlertView solo se mostrará en primer plano. Aún así, el NSLog tampoco se dispara. Supongo que debería funcionar.

+0

¿Se puede incluir el código al que se llama el startMonitoringForRegion? El código incluido en este momento no lo muestra y solo activaría los métodos de devolución de llamada relacionados con cambios de ubicación significativos. Y esos eventos no se dispararán desde el simulador en mi experiencia. –

Respuesta

3

Un amigo mío escribió un buen tutorial sobre el uso de geofencing que podría ayudar a aclarar algunos problemas que está teniendo.

Get started with geofencing

Hay un montón de ejemplos en línea y aquí en la SO. Comience de a poco y siga subiendo. Una vez que comience a recibir sus devoluciones de llamada, puede comenzar a expandir las cosas a sus otros controladores de vista.

ACTUALIZACIÓN

Como se explica en los comentarios de los beneficios de la creación de una clase Singleton para controlar sus administrador y el delegado métodos de localización. Al usar un singleton, evita la posibilidad de recibir múltiples llamadas a sus métodos de delegado. Puede evitar esto con una codificación cuidadosa, pero usar un singleton lo hace por usted. Esta es también una buena clase para manejar todo el trabajo que necesitan hacer sus métodos de delegado.

+2

Gracias por el enlace. Estoy bastante seguro de que tengo todas esas bases cubiertas. En este punto, creo que se trata más de cómo las aplicaciones entran y salen de un fondo que la supervisión de la región. De hecho, tiene bastante sentido para mí que solo funcione en CLLocationManagerDelegate: ¿cómo se supone que debe llamarse a didEnterRegion? ¿Sabe iOS lo suficiente como para activar la aplicación y crear instancias del VC adecuado? Me pregunto si tiene que hacer algo con los protocolos UIApplicationDelegate. –

+1

Por otro lado, UIApplicationDelegate no se menciona en absoluto en la Guía de programación de reconocimiento de ubicación que me lleva a pensar que no es importante. Todavía está confundido en cuanto a cómo se supone que el sistema operativo sabe dónde se implementóEnEnterRegion y cómo acceder a esa clase si la aplicación está en segundo plano ... –

+0

Bastante seguro que va en función de la clase que sea CLLocationManagerDelegate. Esa clase será notificada de cualquier devolución de llamada. Así es como tengo establecido el mío. También creé un singleton para mi clase de administrador de ubicación para evitar recibir múltiples devoluciones de llamada. –

0

Puede publicar una notificación local cuando lo hizoEnterRegion.

Esto mostrará una ventana emergente similar a una alerta, incluso si está en segundo plano.

Usted puede hacer una prueba sencilla:

1) Crear un objeto de notificación local dentro de su applicationDidEnterBackground del delegado de la aplicación, con cualquier mensaje aleatorio y cuentan la notificación local para disparar inmediatamente.

2) Presione el botón de inicio, cuando la aplicación minimiza, debería ver una ventana emergente.

+0

Gracias por las sugerencias: no estaba familiarizado con los protocolos UIApplicationDelegate y ahora me pregunto si no es allí donde está el problema. Echa un vistazo a mis comentarios a Bill Burgess. –

0

creo que necesitas ir a tu aplicación.plist

y añadir modos antecedentes requeridos: añadir quedará grabado aplicación se registra para actualización de ubicación

y 1. si su aplicación está en segundo plano, aún verá la flecha en la parte superior

y 2, si la aplicación se apagó, aún puede ver una flecha hueca en la parte superior, ios supervisará la región por usted, pero limitada a 20 regiones

2

cosas que está haciendo mal:

  1. modos Antecedentes - App registros encontrados para actualizaciones de ubicación. Esto no es necesario Esto es necesario cuando desea recopilar información para cambios significativos en la ubicación, etc. Por lo tanto, vaya a Objetivos> Su aplicación> Capacidades, y seleccione la opción deseada en los modos de Fondo. Esto actualizará automáticamente el plist para usted. Por ahora, deshabilítelo.
  2. Está intentando crear una alerta cuando el usuario ingresa en una región. Mientras esto funciona cuando la aplicación está funcionando, una alerta no sirve cuando tu aplicación está en segundo plano. Do - Más bien desencadenar una notificación local o una llamada api.

por ejemplo. de una notificación:

-(void)triggerLocalNotification:(CLRegion *)region{ 
    UILocalNotification *notification = [[UILocalNotification alloc]init]; 
    [notification setAlertBody:[NSString stringWithFormat:@"Welcome to %@", [region identifier]]]; 
    [notification setRepeatInterval:0]; 
    [notification setFireDate:[NSDate dateWithTimeIntervalSinceNow:2]]; 
    [notification setTimeZone:[NSTimeZone defaultTimeZone]]; 
    [[UIApplication sharedApplication]scheduleLocalNotification:notification]; 
    NSLog(@"notification triggered with notification %@", notification); 
} 
+0

startMonitoringSignificantLocationChanges y startMonitoringForRegion funciona en modo de fondo? –

+0

Si está haciendo startMonitoringSignificantLocationChanges, entonces sí necesita modos en segundo plano. Necesitas que tu aplicación se active cuando la ubicación cambia de manera significativa y tienes que decírselo a tu sistema. Pero no lo necesita para startMonitoringForRegion. startMonitoringForRegion llamará a didEnterRegion y didExitRegion independientemente de los modos de fondo. –

+0

Muchas gracias, quiero utilizar CLLocationManager con un consumo mínimo de batería. –

Cuestiones relacionadas