iOS 11-添加委托后未收到位置更新 [英] iOS 11 - Location update not received after adding delegate

查看:58
本文介绍了iOS 11-添加委托后未收到位置更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在iOS 11中,使用时允许和始终允许的定位服务一直存在问题。在iOS中<可以正常工作11.按照此



PS上面代码中的Log函数是NSLog函数的包装,因为我也使用我的方法来写文件。



祝你好运,乌玛,让我知道去。



问候,Heider


I have been having trouble with location services in iOS 11 for both "Allow while Use" and "Always Allow". Works without issue in iOS < 11. Followed this thread in trying to fix but still doesn't work. What am I missing? Thank you in advance.

  1. I have UITabViewController in my app and a UINavigationController inside each tab.
  2. I have a singleton LocationManager class. I'm setting my UINavigationController's RootViewController as delegate the ViewController's viewWillAppear to receive location updates and removing in viewWillDisappear.
  3. Now, When I launch the app, before the tab bar is created, I can see the location update is being called in the LocationManager Class.
  4. But when I add my UIViewController as delegate and give startUpdatingLocation I'm not receiving the location update in my UIVIewController.
  5. Then I press Home button and exit the app. Again immediately launch the app and I get the location update in my delegate method.

I have added all three location authorization description in my 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];
}

解决方案

I had one of the new devices reported this problem, as you know the the Location Manager usually calls this:

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

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

1) userLocation.location.coordinate: This used to work fine, but for some reason it's returning NULL on IOS11 on some devices (it's unknown yet why or how this is behaving since IOS11).

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

So, with the example above, "I guess" that your:

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

Might be having the same problem (i.e. the array might be returning a NULL somewhere in the location object, but not the coordinate object, the solution I did on my code which gets one location at a time, is now fixed by by replacing userLocation.location.coordinate with userLocation.coordinate, and the problem gone away.

I also paste my function below to assist you further, hopefully it would help you to resolve yours too, notice that I have two conditions for testing one for sourcing the location object and the other for sourcing the 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, have you checked your settings for the Map object, you should have at least "User Location" enabled:

P.S. The Log function on the code above is a wrapper to the NSLog function, as I use mine to write to files as well.

Good luck Uma, let me know how it goes.

Regards, Heider

这篇关于iOS 11-添加委托后未收到位置更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆