IOS 11 - Location update not received after adding delegate

I'm having issues with location services in iOS 11 for "Allow use for now" and "Always allow." It works without problems in iOS <11. After that, thread tried to fix it, but still does not work. What am I missing? Thank you in advance.

  • I have a UITabViewController in my application and a UINavigationController inside each tab.
  • I have a singleton LocationManager class. I set my UINavigationController RootViewController as a delegate of ViewController viewWillAppear to receive location updates and delete in viewWillDisappear .
  • Now, when I launch the application, before creating the tab bar, I see that the location update is called in the LocationManager class.
  • But when I add my UIViewController as a delegate and give startUpdatingLocation , I don't get the location update in my UIVIewController.
  • Then click the "Home" button and exit the application. Run the application again immediately, and I get a location update in my delegate method.

I have added all three location authorization descriptions to the Info.plist file.

info.plist:

 <key>NSLocationAlwaysAndWhenInUseUsageDescription</key> <string>Blah Blah Blah</string> <key>NSLocationAlwaysUsageDescription</key> <string>Blah Blah Blah</string> <key>NSLocationWhenInUseUsageDescription</key> <string>Blah Blah Blah</string> 

LocationController.m:

 #import "LocationController.h" //static int LOCATION_ACCESS_DENIED = 1; //static int LOCATION_NETWORK_ISSUE = 2; //static int LOCATION_UNKNOWN_ISSUE = 3; enum { LOCATION_ACCESS_DENIED = 1, LOCATION_NETWORK_ISSUE = 2, LOCATION_UNKNOWN_ISSUE = 3 }; static LocationController* sharedCLDelegate = nil; @implementation LocationController int distanceThreshold = 10.0; // in meters @synthesize locationManager, currentLocation, locationObservers; - (id)init { self = [super init]; if (self != nil) { self.locationManager = [[CLLocationManager alloc] init]; self.locationManager.desiredAccuracy = kCLLocationAccuracyBest; self.locationManager.distanceFilter = distanceThreshold; self.locationManager.pausesLocationUpdatesAutomatically = NO; [self.locationManager startMonitoringSignificantLocationChanges]; self.locationManager.delegate = (id)self; if ([self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) { [self.locationManager requestWhenInUseAuthorization]; //I tried both commenting this line and uncommenting this line. Didn't make any difference } if ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) { [self.locationManager requestAlwaysAuthorization]; } [self.locationManager startUpdatingLocation]; [self.locationManager startUpdatingHeading]; locationObservers = [[NSMutableArray alloc] init]; } return self; } #pragma mark - #pragma mark CLLocationManagerDelegate Methods - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations { NSLog(@"locationManager didUpdateLocations = %@",locations); CLLocation *newLocation = [locations lastObject]; if (newLocation.horizontalAccuracy < 0) { return; } currentLocation = newLocation; for(id<LocationControllerDelegate> observer in self.locationObservers) { if (observer) { // CLLocation *newLocation = [locations lastObject]; // if (newLocation.horizontalAccuracy < 0) { // return; // } // currentLocation = newLocation; NSTimeInterval interval = [currentLocation.timestamp timeIntervalSinceNow]; //check against absolute value of the interval if (fabs(interval)<30) { [observer locationUpdate:currentLocation]; } } } } - (void)locationManager:(CLLocationManager*)manager didFailWithError:(NSError*)error { NSLog(@"locationManager didFailWithError: %@", error); for(id<LocationControllerDelegate> observer in self.locationObservers) { if (observer) { [observer failedToGetLocation:error]; } } switch (error.code) { case kCLErrorDenied: { break; } case kCLErrorNetwork: { break; } default: break; } } #pragma mark - Singleton implementation in ARC + (LocationController *)sharedLocationInstance { static LocationController *sharedLocationControllerInstance = nil; static dispatch_once_t predicate; dispatch_once(&predicate, ^{ sharedLocationControllerInstance = [[self alloc] init]; }); return sharedLocationControllerInstance; } -(void) locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status { NSLog(@"didChangeAuthorizationStatus = %i",status); if (status == kCLAuthorizationStatusAuthorizedAlways || status == kCLAuthorizationStatusAuthorizedWhenInUse) { [self.locationManager stopUpdatingLocation]; [self.locationManager startUpdatingLocation]; } } - (void) addLocationManagerDelegate:(id<LocationControllerDelegate>)delegate { if (![self.locationObservers containsObject:delegate]) { [self.locationObservers addObject:delegate]; } [self.locationManager startUpdatingLocation]; } - (void) removeLocationManagerDelegate:(id<LocationControllerDelegate>)delegate { if ([self.locationObservers containsObject:delegate]) { [self.locationObservers removeObject:delegate]; } } + (id)allocWithZone:(NSZone *)zone { @synchronized(self) { if (sharedCLDelegate == nil) { sharedCLDelegate = [super allocWithZone:zone]; return sharedCLDelegate; // assignment and return on first allocation } } return nil; // on subsequent allocation attempts return nil } - (id)copyWithZone:(NSZone *)zone { return self; } #pragma mark UIAlertViewDelegate Methods - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { switch (alertView.tag) { case LOCATION_ACCESS_DENIED: { if (buttonIndex == 1) { //[[UIApplication sharedApplication] openURL: [NSURL URLWithString: UIApplicationOpenSettingsURLString]]; [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"prefs:root=LOCATION_SERVICES"]]; } } break; case LOCATION_NETWORK_ISSUE: break; case LOCATION_UNKNOWN_ISSUE: break; default: break; } [alertView dismissWithClickedButtonIndex:buttonIndex animated:YES]; } @end 

LocationController.h

 #import <UIKit/UIKit.h> #import <CoreLocation/CoreLocation.h> #import <Foundation/Foundation.h> // protocol for sending location updates to another view controller @protocol LocationControllerDelegate @required - (void)locationUpdate:(CLLocation*)location; - (void)failedToGetLocation:(NSError*)error; @end @interface LocationController : NSObject<CLLocationManagerDelegate,UIAlertViewDelegate> @property (nonatomic, strong) CLLocationManager* locationManager; @property (nonatomic, strong) CLLocation* currentLocation; @property (strong, nonatomic) NSMutableArray *locationObservers; + (LocationController*)sharedLocationInstance; // Singleton method - (void) addLocationManagerDelegate:(id<LocationControllerDelegate>) delegate; - (void) removeLocationManagerDelegate:(id<LocationControllerDelegate>) delegate; @end 

ViewController.m

 - (void) viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; NSLog(@"VC viewWillAppear"); [locationControllerInstance addLocationManagerDelegate:self]; } 

AppDelegate.m

 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [LocationController sharedLocationInstance]; } 
0
ios objective-c cllocationmanager ios11
07 Oct '17 at 3:52
source share
1 answer

I had one of the new devices reporting this problem since, as you know, the location manager usually calls this:

- (void) mapView: (MKMapView *) mapView didUpdateUserLocation: (MKUserLocation *) userLocation

The strangest thing is that the UserLocation object contains two coordinate objects:

1) userLocation.location.coordinate: This works fine, but for some reason returns NULL on IOS11 on some devices (it is not yet known why and how this happens with IOS11).

2) userLocation.coordinate: This is another (the same) object that you can see from the properties, it has location data and continues to work fine with IOS11, it does not seem to be broken (yet).

So, in the example above, "I think" that your:

  • (void) locationManager: (CLLocationManager *) manager didUpdateLocations: (NSArray *) locations

Perhaps you have the same problem (i.e. the array may return NULL somewhere in the location object, but not the coordinate object, the decision I made in my code that gets one location at a time is now fixed by replacing userLocation.location .coordinate on userLocation.coordinate and the problem disappeared.

I also insert my function below to help you, I hope this helps you solve your problem, please note that I have two conditions for testing one for finding a location object, and the other for finding a coordinate object, one works fine now, and the other seems to be broken in iOS11:

 -(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation { Log (4, @"MapView->DidUpdateUL - IN"); if (_OrderStartTrackingMode == enuUserMapTrackingMode_User) { if (userLocation) { if (userLocation.location) { if ( (userLocation.location.coordinate.latitude) && (userLocation.location.coordinate.longitude)) { [_mapLocations setCenterCoordinate:userLocation.location.coordinate animated:YES]; } else { if ( (userLocation.coordinate.latitude) && (userLocation.coordinate.longitude)) { [self ShowRoutePointsOnMap:userLocation.coordinate]; } } } } } else if (_OrderStartTrackingMode == enuUserMapTrackingMode_Route) { if (userLocation) { if ( (userLocation.coordinate.latitude) && (userLocation.coordinate.longitude)) { [self ShowRoutePointsOnMap:userLocation.coordinate]; } } } Log (4, @"MapView->DidUpdateUL - OUT"); } 

Needless to say, that you checked your settings for the Map object, you should have at least "User Location" enabled:

enter image description here

PS The Log function in the above code is a shell of the NSLog function, since I use mine to write to files.

Good luck, Uma, let me know how this happens.

Regards, Hyder

+1
Oct 07 '17 at 21:17
source share



All Articles