7

All of my code is in AppDelegate.m:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    self.window = [[UIWindow alloc]initWithFrame:[[UIScreen mainScreen]bounds]];

    _locationMgr = [[CLLocationManager alloc] init];
    [_locationMgr setDelegate:self];
    if([_locationMgr respondsToSelector:@selector(setAllowsBackgroundLocationUpdates:)])
        [_locationMgr setAllowsBackgroundLocationUpdates:YES];
    CLAuthorizationStatus authorizationStatus= [CLLocationManager authorizationStatus];

    if([launchOptions valueForKey:UIApplicationLaunchOptionsLocationKey] != nil) {
        NSLog(@"relaunching because of significant location change - restarting SLC");
        [_locationMgr startMonitoringSignificantLocationChanges];
    }
    else
    {
        if (authorizationStatus == kCLAuthorizationStatusAuthorizedAlways) {
            NSLog(@"launching with authorization to always use location - starting SLC");
            [_locationMgr startMonitoringSignificantLocationChanges];
        }
        else
        {
            NSLog(@"launching with no authorization to always use location - requesting authorization");
            if([_locationMgr respondsToSelector:@selector(requestAlwaysAuthorization)])
                [_locationMgr requestAlwaysAuthorization];
        }
    }

    if([userdefaults objectForKey:@"pfuser"] == nil) {
        NSLog(@"in delegate signup");
        SignUpController *signup = [[SignUpController alloc] init];
        [self.window setRootViewController:signup];
    }
    else {
        ViewController *map = [[ViewController alloc] init];
        [self.window setRootViewController:map];
    }
    [self.window makeKeyAndVisible];

    return YES;
}

- (void)startSignificantChangeUpdates
{
    deviceNotFoundAlertController = [UIAlertController alertControllerWithTitle:@"START" message:@"startSignificantChangeUpdates called" preferredStyle:UIAlertControllerStyleAlert];

    [deviceNotFoundAlertController addAction:deviceNotFoundAlert];
    // Create the location manager if this object does not
    // already have one.
    if (nil == _locationMgr) {
        _locationMgr = [[CLLocationManager alloc] init];
        _locationMgr.delegate = self;
    }

    [CLLocationManager significantLocationChangeMonitoringAvailable];
    [_locationMgr startMonitoringSignificantLocationChanges];
}

-(void)locationManger:(CLLocationManager *)manager didFailWithError:(NSError *)error {
    NSLog(@"didFailWithError: %@", error);
    deviceNotFoundAlertController = [UIAlertController alertControllerWithTitle:@"LOCATION FAIL" message:@"didFailWithError" preferredStyle:UIAlertControllerStyleAlert];

    [deviceNotFoundAlertController addAction:deviceNotFoundAlert];
}

// Delegate method from the CLLocationManagerDelegate protocol.
- (void)_locationManager:(CLLocationManager *)manager
      didUpdateLocations:(NSArray *)locations {
    deviceNotFoundAlertController = [UIAlertController alertControllerWithTitle:@"LOCATION UPDATE" message:@"didUpdateLocations called" preferredStyle:UIAlertControllerStyleAlert];

    [deviceNotFoundAlertController addAction:deviceNotFoundAlert];
    // If it's a relatively recent event, turn off updates to save power.
    CLLocation* location = [locations lastObject];
    NSDate* eventDate = location.timestamp;
    NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];
    if (fabs(howRecent) < 15.0) {
        // If the event is recent, do something with it.
        NSLog(@"latitude %+.6f, longitude %+.6f\n",
              location.coordinate.latitude,
              location.coordinate.longitude);
    }
}

None of the alerts happen, it seems like the delegate methods aren't being called.

UPDATE

Now I have:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    self.window = [[UIWindow alloc]initWithFrame:[[UIScreen mainScreen]bounds]];

    deviceNotFoundAlert = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil];

    ...

}

// Delegate method from the CLLocationManagerDelegate protocol.
- (void)locationManager:(CLLocationManager *)manager
      didUpdateLocations:(NSArray *)locations {
    deviceNotFoundAlertController = [UIAlertController alertControllerWithTitle:@"LOCATION UPDATE" message:@"didUpdateLocations called" preferredStyle:UIAlertControllerStyleAlert];

    [deviceNotFoundAlertController addAction:deviceNotFoundAlert];
    // If it's a relatively recent event, turn off updates to save power.
    CLLocation* location = [locations lastObject];
    NSDate* eventDate = location.timestamp;
    NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];
    if (fabs(howRecent) < 15.0) {
        // If the event is recent, do something with it.
        NSLog(@"latitude %+.6f, longitude %+.6f\n",
              location.coordinate.latitude,
              location.coordinate.longitude);
    }
}

When I test the app, I open it at my house, and then close it, so that when I leave my house it should send an alert (or 3) at some point, but I am not getting alerts from any of the delegate methods (where I placed alerts).

I just had an idea, maybe I have to display the alerts from the main UIViewController, not the AppDelegate?

This may be why I am not seeing the alerts: How do I add a UIAlertController in app delegate (obj-c)

UPDATE

This is how I am doing the alerts now:

deviceNotFoundAlertController = [UIAlertController alertControllerWithTitle:@"START" message:@"startSignificantChangeUpdates called" preferredStyle:UIAlertControllerStyleAlert];

[deviceNotFoundAlertController addAction:deviceNotFoundAlert];

alertWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
alertWindow.rootViewController = [[UIViewController alloc] init];
alertWindow.windowLevel = UIWindowLevelAlert + 1;
[alertWindow makeKeyAndVisible];
[alertWindow.rootViewController presentViewController:deviceNotFoundAlertController animated:YES completion:nil];

UPDATE

The alerts did not seem to be the issue, the alert in startSignificantChangeUpdates never appears. Should it appear once I am 500m from my initial location?

UPDATE

Can anyone help me understand this?

The methods of your delegate object are called from the thread in which you started the corresponding location services. That thread must itself have an active run loop, like the one found in your application’s main thread.

UPDATE

I think I figured out what the above quote is saying...and I have this now - I will test tomorrow.

...

if([launchOptions valueForKey:UIApplicationLaunchOptionsLocationKey] != nil) {
        NSLog(@"relaunching because of significant location change - restarting SLC");
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [_locationMgr startMonitoringSignificantLocationChanges];
        });
    }
    else
    {
        if (authorizationStatus == kCLAuthorizationStatusAuthorizedAlways) {
            NSLog(@"launching with authorization to always use location - starting SLC");
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                [_locationMgr startMonitoringSignificantLocationChanges];
            });
        }
        else
        {
            NSLog(@"launching with no authorization to always use location - requesting authorization");
            if([_locationMgr respondsToSelector:@selector(requestAlwaysAuthorization)])
                [_locationMgr requestAlwaysAuthorization];
        }
    }

...

I think that code is starting the location services on its own thread. One thing I noticed already, is that when I exit the app, the location in the top right goes away. I just updated to iOS 10. In iOS 9 the location arrow in the top right would stay there, but it would only be a black outline when the app was not running. This could just be something they changed with iOS 10, or now because I updated to 10, something else isn't working now. Or that is what happens when the location services are run on their own thread. From here: iOS start Background Thread

UPDATE

Maybe I am not using the thread correctly, but as I said, now when I close the app, location services quits. When I was doing it without the thread the location service arrow would stay in the top right, as an outline.

UPDATE

I read that the service should be started on the main thread - so now I have:

CLAuthorizationStatus authorizationStatus= [CLLocationManager authorizationStatus];

    NSLog(@"launching with no authorization to always use location - requesting authorization");
    if([_locationMgr respondsToSelector:@selector(requestAlwaysAuthorization)]) {
        [_locationMgr requestAlwaysAuthorization];
    }

    if([launchOptions valueForKey:UIApplicationLaunchOptionsLocationKey] != nil) {
        NSLog(@"relaunching because of significant location change - restarting SLC");
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [_locationMgr startMonitoringSignificantLocationChanges];
        });
    }
    else if (authorizationStatus == kCLAuthorizationStatusAuthorizedAlways) {
        NSLog(@"launching with authorization to always use location - starting SLC");
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [_locationMgr startMonitoringSignificantLocationChanges];
        });
    }
    else {
        //
    }

The arrow in the right doesn't show up when the app is closed, is this something new to iOS 10 where they don't show it anymore?

UPDATE

I accidentally deleted: _locationMgr = [[CLLocationManager alloc] init]; I put in and now the arrow is always there, going to test today.

UPDATE

I tested it, still no alerts.

Community
  • 1
  • 1
ewizard
  • 2,801
  • 4
  • 52
  • 110
  • Did you configure to use the location service in the plist?? If not then you need to do it. There are two option requestAlwaysAuthorization and requestWhenInUseAuthorization. Let me know if that solves your issue – Janmenjaya Sep 17 '16 at 17:53
  • Hi, yes I have - when I type it in it changes to `Privacy - Location Always Usage Description` and I put a message in the other column...there is actually something slightly different now...i think i need to test again ill let you know – ewizard Sep 17 '16 at 20:36
  • I also have `Required background modes` with` Item0` and `App registers for location updates` – ewizard Sep 17 '16 at 20:39

4 Answers4

2

It is a problem with your delegate method please replace below one

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

with

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

Hope it will help you.

Vishnuvardhan
  • 5,081
  • 1
  • 17
  • 33
  • I made the change - but I still am not getting any alerts. Also, shouldn't I have gotten an alert from `startSignificantChangeUpdates`? – ewizard Sep 20 '16 at 19:39
  • I may have got it working, i need to test again...one major problem was that i never instantiated `deviceNotFoundAlert` – ewizard Sep 20 '16 at 19:52
  • Still not working, no alerts from any delegate method – ewizard Sep 20 '16 at 22:08
  • check whether "didUpdateLocations" method is calling or not. And If get's called so you are creating object for "alertviewcontroller" but where do u present alert? – Vishnuvardhan Sep 21 '16 at 04:13
  • I noticed this too, I was trying to display it in the delegate...I need to display it in the view controller, I have written that in and im about to test it...ill update my question to show what I have for the alert...im pretty sure its right just havent been able to test yet – ewizard Sep 21 '16 at 14:15
  • So i am well beyond 500m from my house now, and no alert - so im back to thinking something is wrong with the delegate – ewizard Sep 21 '16 at 16:27
2

I took my computer with me in my car, and watched the console, and I saw that the significant location changes are happening now because I get location updates every 500m. The alerts are the only thing not working, but they are irrelevant to the program - they were just there to see if it was working. It is working with this code:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    self.window = [[UIWindow alloc]initWithFrame:[[UIScreen mainScreen]bounds]];

    ...

    _locationMgr = [[CLLocationManager alloc] init];
    [_locationMgr setDelegate:self];

    if([_locationMgr respondsToSelector:@selector(setAllowsBackgroundLocationUpdates:)])
        [_locationMgr setAllowsBackgroundLocationUpdates:YES];

    CLAuthorizationStatus authorizationStatus= [CLLocationManager authorizationStatus];

    NSLog(@"launching with no authorization to always use location - requesting authorization");
    if([_locationMgr respondsToSelector:@selector(requestAlwaysAuthorization)]) {
        [_locationMgr requestAlwaysAuthorization];
    }

    if([launchOptions valueForKey:UIApplicationLaunchOptionsLocationKey] != nil) {
        NSLog(@"relaunching because of significant location change - restarting SLC");
        [_locationMgr startMonitoringSignificantLocationChanges];
    }
    else if (authorizationStatus == kCLAuthorizationStatusAuthorizedAlways) {
        NSLog(@"launching with authorization to always use location - starting SLC");
        [_locationMgr startMonitoringSignificantLocationChanges];
    }
    else {
        //
    }

    ...

    [self.window makeKeyAndVisible];

    return YES;
}

- (void)startSignificantChangeUpdates
{
    // Create the location manager if this object does not
    // already have one.
    if (nil == _locationMgr) {
        _locationMgr = [[CLLocationManager alloc] init];
        _locationMgr.delegate = self;
    }

    [CLLocationManager significantLocationChangeMonitoringAvailable];

    [_locationMgr startMonitoringSignificantLocationChanges];

    deviceNotFoundAlertController = [UIAlertController alertControllerWithTitle:@"START" message:@"startSignificantChangeUpdates called" preferredStyle:UIAlertControllerStyleAlert];

}

-(void)locationManger:(CLLocationManager *)manager didFailWithError:(NSError *)error {
    NSLog(@"didFailWithError: %@", error);
}

// Delegate method from the CLLocationManagerDelegate protocol.
- (void)locationManager:(CLLocationManager *)manager
      didUpdateLocations:(NSArray *)locations {

    // If it's a relatively recent event, turn off updates to save power.
    CLLocation* location = [locations lastObject];
    NSDate* eventDate = location.timestamp;
    NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];
    if (fabs(howRecent) < 15.0) {
        // If the event is recent, do something with it.
        NSLog(@"latitude %+.6f, longitude %+.6f\n",
              location.coordinate.latitude,
              location.coordinate.longitude);
    }
}
ewizard
  • 2,801
  • 4
  • 52
  • 110
1
You have written write code, Just add below delegate method in your code.  But startMonitoringSignificantLocationChanges for updating location take 10 to 20 min. and also trigger if location channel change.

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

}
Kiran K
  • 919
  • 10
  • 17
1

[_locationMgr startMonitoringSignificantLocationChanges];

The significant-change location service delivers updates only when there has been a significant change in the device’s location, such as 500 meters or more.

So your delegate method will call each time once when your device moved more than 500 meter.

Make sure your app have background location permission.

if your app is in background or foreground then it will call delegate method otherwise app will launch with location option in AppDelegate file where you have to create Location manager object and start location again to get new location.

https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/LocationAwarenessPG/CoreLocation/CoreLocation.html

Kiran Patel
  • 944
  • 10
  • 16
  • i have background permission, it doesnt work after 500m+ - does my code look right? – ewizard Sep 24 '16 at 00:28
  • Call local notification in location delegate method, make sure new delegate method . and move about 2+ KM. It says 500+meter it dosen't call exact 500 meter, sometimes takes more distance depending upon network service. So you can identify. Its working I tested it – Kiran Patel Oct 04 '16 at 17:55