未调用重大更改位置委托方法
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”