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.