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

7

我的所有代码都在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显示警报?
这可能是我没有看到警报的原因:如何在应用程序委托中添加UIAlertController (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的警报从未出现。当我距离初始位置500米时,它是否应该出现?

更新

有人能帮我理解一下吗?

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

更新

我想我已经理解了上面的引用所说的内容...而且我现在有这个 - 我明天会测试。

...

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。如果这样做可以解决您的问题,请告诉我。 - Janmenjaya
嗨,是的,我有 - 当我输入它时,它会更改为“隐私 - 始终使用位置说明”,然后我在另一列中放置了一条消息...现在实际上有些不同了...我认为我需要再次测试,我会让你知道。 - ewizard
我还有所需的背景模式应用程序注册位置更新,其中包含Item0 - ewizard
4个回答

2
这是一个与委托方法有关的问题,请使用以下替代方法。
- (void)_locationManager:(CLLocationManager *)manager
      didUpdateLocations:(NSArray *)locations {
}

使用

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

希望这能对您有所帮助。


我已经做出了改变,但是我仍然没有收到任何警报。另外,我不应该从startSignificantChangeUpdates中收到一个警报吗? - ewizard
我可能已经让它工作了,但我需要再次测试一下……一个主要的问题是我从未实例化deviceNotFoundAlert - ewizard
仍然无法工作,没有任何委托方法发出警报。 - ewizard
检查 "didUpdateLocations" 方法是否被调用。如果被调用,则创建 "alertviewcontroller" 对象,但是在哪里呈现警报? - Vishnuvardhan
我也注意到了这一点,我试图在委托中显示它...但我需要在视图控制器中显示它,我已经写好了代码并且即将进行测试...我会更新我的问题以展示我为警报所做的工作...我相当确定它是正确的,只是还没有能够测试。 - ewizard
我现在已经离家超过500米了,但没有任何警报 - 所以我又开始认为代表出了问题。 - ewizard

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

1

[_locationMgr startMonitoringSignificantLocationChanges];

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

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

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

如果您的应用程序在后台或前台,则会调用委托方法。 否则,应用程序将在AppDelegate文件中使用位置选项启动,在那里您必须创建Location manager对象并重新启动位置以获取新位置。

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


我已经获取了后台权限,但在500米以上它不起作用了 - 我的代码看起来正确吗? - ewizard
在位置委托方法中调用本地通知,确保新的委托方法。并且移动大约2公里。它说500米,它不会准确地呼叫500米,有时会根据网络服务而需要更多的距离。所以你可以识别。它正在工作,我已经测试过了。 - Kiran Patel

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
{

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接