未调用重大更改位置委托方法

Posted

技术标签:

【中文标题】未调用重大更改位置委托方法【英文标题】:significant change location delegate methods not being called 【发布时间】:2016-09-17 16:54:50 【问题描述】:

我所有的代码都在 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);
    

没有任何警报发生,似乎没有调用委托方法。

更新

现在我有:

- (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);
    

当我测试应用程序时,我会在我家打开它,然后将其关闭,这样当我离开家时,它应该会在某个时候发送警报(或 3 个),但我没有收到来自任何人的警报委托方法(我放置警报的地方)。

我刚刚有个想法,也许我必须显示来自主要UIViewController 的警报,而不是来自AppDelegate

这可能是我看不到警报的原因:How do I add a UIAlertController in app delegate (obj-c)

更新

这就是我现在做警报的方式:

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];

更新

警报似乎不是问题,startSignificantChangeUpdates 中的警报从未出现。它应该在我距离初始位置 500m 时出现吗?

更新

谁能帮我理解这个?

您的委托对象的方法是从您启动相应位置服务的线程中调用的。该线程本身必须有一个活动的运行循环,就像在您的应用程序的主线程中找到的那样。

更新

我想我明白上面引用的意思了......我现在知道了 - 我明天会测试。

...

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];
        
    

...

我认为代码是在自己的线程上启动定位服务。我已经注意到的一件事是,当我退出应用程序时,右上角的位置消失了。我刚刚更新到 ios 10。在 iOS 9 中,右上角的位置箭头会保留在那里,但当应用程序未运行时,它只会是黑色轮廓。这可能只是他们用 iOS 10 改变的东西,或者现在因为我更新到 10,其他东西现在不起作用。或者这就是位置服务在它们自己的线程上运行时发生的情况。从这里:iOS start Background Thread

更新

也许我没有正确使用线程,但正如我所说,现在当我关闭应用程序时,定位服务会退出。当我在没有线程的情况下执行此操作时,位置服务箭头将保留在右上角,作为轮廓。

更新

我读到该服务应该在主线程上启动 - 所以现在我有:

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 
        //
    

关闭应用后右侧的箭头不显示,这是 iOS 10 的新功能,不再显示了吗?

更新

我不小心删除了:_locationMgr = [[CLLocationManager alloc] init];我输入了,现在箭头一直在,今天去测试。

更新

我测试了它,仍然没有警报。

【问题讨论】:

您是否配置为使用 plist 中的定位服务?如果没有,那么你需要这样做。有两个选项 requestAlwaysAuthorization 和 requestWhenInUseAuthorization。让我知道这是否能解决您的问题 嗨,是的,我有 - 当我输入它时,它会更改为 Privacy - Location Always Usage Description,然后我在另一列中输入了一条消息......现在实际上有些不同......我想我需要再次测试生病让你知道 我也有 Required background modes with`Item0` 和 App registers for location updates 【参考方案1】:

你的代理方法有问题,请替换下面的一个

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

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

希望对你有所帮助。

【讨论】:

我进行了更改 - 但我仍然没有收到任何警报。另外,我不应该收到来自startSignificantChangeUpdates 的警报吗? 我可能已经成功了,我需要再次测试...一个主要问题是我从未实例化 deviceNotFoundAlert 仍然无法正常工作,没有来自任何委托方法的警报 检查“didUpdateLocations”方法是否正在调用。如果调用了 get,那么您正在为“alertviewcontroller”创建对象,但是您在哪里显示警报? 我也注意到了这一点,我试图在委托中显示它...我需要在视图控制器中显示它,我已经将其写入并且我即将对其进行测试...生病了更新我的问题以显示我对警报有什么...我很确定它是正确的,只是还没有能够测试【参考方案2】:

我在车里带着我的电脑,看着控制台,我看到现在正在发生重大的位置变化,因为我每 500 米就会更新一次位置。警报是唯一不工作的东西,但它们与程序无关 - 它们只是在那里查看它是否工作。它正在使用此代码:

- (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);
    

【讨论】:

【参考方案3】:
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



【讨论】:

【参考方案4】:

[_locationMgr startMonitoringSignificantLocationChanges];

重大变化位置服务仅在设备位置发生重大变化(例如 500 米或更多)时才会提供更新。

因此,当您的设备移动超过 500 米时,您的委托方法每次都会调用一次。

确保您的应用具有后台位置权限。

如果您的应用程序在后台或前台,那么它将调用委托方法 否则应用程序将在 AppDelegate 文件中使用位置选项启动,您必须在其中创建位置管理器对象并再次启动位置以获取新位置。

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

【讨论】:

我有后台权限,在 500m+ 后它不起作用 - 我的代码看起来正确吗? 在位置委托方法中调用本地通知,确保新的委托方法。并移动约 2+ KM。它说 500+ 米它不称为确切的 500 米,有时需要更多的距离,具体取决于网络服务。这样你就可以识别了。它的工作我测试了它

以上是关于未调用重大更改位置委托方法的主要内容,如果未能解决你的问题,请参考以下文章

未调用 CLLocation Manager didStartMonitoringForRegion 委托方法

UICollectionView 的 99% CPU 使用率 - 显着位置更改未调用“didUpdateLocations”

监视重大位置更改时不会调用“didUpdateLocations”

CLLocationManager委托方法未被调用

ios 7中的重大位置更改事件-后台服务调用

UIDocumentPickerViewController - 未调用委托方法