简体   繁体   English

CLLocationManager位置监视无法正常工作

[英]CLLocationManager location monitoring not working properly

I have an app that will notify the user every time he approaches to one of my client's stores. 我有一个应用程序,每次用户访问我的客户商店之一时,都会通知用户。 There are more than 20 stores, so I have a function that takes the user's location and finds the 20 nearest stores to him and start monitoring the location of these stores, every time the user moves, the app finds the 20 nearest stores again, removes the previous stores from monitoring and start monitoring the new ones. 有超过20家商店,所以我有一个功能,可以获取用户的位置并找到距他最近的20家商店,并开始监视这些商店的位置,每当用户移动时,应用程序都会再次找到20家最近的商店,并删除从以前的商店监视并开始监视新的商店。

For some reason, it doesn't work, I'll be happy if one of you (or more :)) will help me to find the problem, Thanks!! 由于某些原因,它不起作用,如果你们中的一个(或多个:))能帮助我找到问题,我会很高兴的,谢谢!

myCode (scroll to see the full code): myCode (滚动查看完整代码):

Note: the CLLocationManager created on the AppDelegate.m and it's delegate is this class ( UIViewController ). 注意:在AppDelegate.m上创建的CLLocationManager及其委托是此类( UIViewController )。

-(void)sortClosestStores
{
    [self.allStores sortUsingComparator:^NSComparisonResult(id  _Nonnull obj1, id  _Nonnull obj2) {
        CLLocation *location1=[[CLLocation alloc] initWithLatitude:((Store*)obj1).geoPoint.latitude longitude:((Store*)obj1).geoPoint.longitude];
        CLLocation *location2=[[CLLocation alloc] initWithLatitude:((Store*)obj2).geoPoint.latitude longitude:((Store*)obj2).geoPoint.longitude];

    float dist1 =[location1 distanceFromLocation:self.locationManager.location];
    float dist2 = [location2 distanceFromLocation:self.locationManager.location];
    if (dist1 == dist2) {
        return NSOrderedSame;
    }
    else if (dist1 < dist2) {
        return NSOrderedAscending;
    }
    else {
        return NSOrderedDescending;
    }
}];

if (self.twentyClosestStores==nil) {
    self.twentyClosestStores=[NSMutableArray array];
}

if (self.previousTwentyStores==nil) {
    self.previousTwentyStores=[NSMutableArray array];
}
self.previousTwentyStores=self.twentyClosestStores;
self.twentyClosestStores=[NSMutableArray array];

for (int i = 0; i < 20; i++) {
    [self.twentyClosestStores addObject:[self.allStores objectAtIndex:i]];
    }
}

-(void)startMonitoringClosestStores
{
    if (![CLLocationManager isMonitoringAvailableForClass:[CLCircularRegion class]]) {
        NSLog(@"Monitoring is not available for CLCircularRegion class");
    }

    for (Store *currentStore in self.twentyClosestStores) {
        CLCircularRegion *region=[currentStore createCircularRegion];
         [self.locationManager startMonitoringForRegion:region];
    }
}
-(void)stopMonitoringStores
{
    for (Store *currentStore in self.previousTwentyStores) {
        CLCircularRegion *region=[currentStore createCircularRegion];
        [self.locationManager stopMonitoringForRegion:region];
    }
}

-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
    if (self.allStores!=nil) {
        [self sortClosestStores];
        [self stopMonitoringStores];
        [self startMonitoringClosestStores];
    }
}


-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
    NSLog(@"Entered"); //Not called even when the user enters one of the regions.
}

Can you please help me? 你能帮我么? Thanks! 谢谢!

I'm pretty new at CoreLocation myself but I would think that it is not a good idea to call stopMonitoringForRegions and startMonitoringForRegions in didUpdateLocations. 我本人在CoreLocation上还很新,但是我认为在didUpdateLocations中调用stopMonitoringForRegions和startMonitoringForRegions不是一个好主意。

Since you're monitoring regions, the didEnterRegion delegate is what you will be interested in. That will give you the 'hey, I arrived at the X store' event, and in there is where you would probably want to call the code that you currently have in your didUpdateLocations. 由于您正在监视区域,因此您将对didEnterRegion委托感兴趣。这将为您提供“嘿,我到达X商店”事件,并且您可能希望在其中调用您所需要的代码当前在您的didUpdateLocations中。

You will want to setup CoreLocation probably in your AppDelegate, so you might have something like (sorry about it being Swift, that's what I'm working in right now): 您可能需要在AppDelegate中设置CoreLocation,所以可能会有类似的东西(对不起,它是Swift,这就是我现在正在使用的东西):

locationManager.delegate = self
// auths:
locationManager.requestAlwaysAuthorization()
locationManager.requestWhenInUseAuthorization()
// config:
locationManager.distanceFilter = kCLDistanceFilterNone
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.pausesLocationUpdatesAutomatically = true
locationManager.allowsBackgroundLocationUpdates = true
locationManager.activityType = CLActivityType.AutomotiveNavigation

// start:
locationManager.startMonitoringSignificantLocationChanges()

Then you would have your code: 然后,您将获得代码:

if (self.allStores!=nil) {
    [self sortClosestStores];
    [self stopMonitoringStores];
    [self startMonitoringClosestStores];
}

Note: I don't think it matters if you call startMonitoringSignificantLocationChanges before or after adding monitored regions, I haven't gotten quite that far in my code yet. 注意:如果您在添加受监视区域之前或之后调用startMonitoringSignificantLocationChanges,那么我认为这并不重要,我的代码还没有那么完善。

didUpdateLocations is more for when you want to track location eg tracking a bicycle ride or jogging session. didUpdateLocations适用于想要跟踪位置的情况,例如跟踪自行车骑行或慢跑。

Additional explanation: OK, I think I understand the issue now. 附加说明:好的,我想我现在已经理解了这个问题。 There are two aspects to what you want to accomplish: 您要完成的工作有两个方面:

  • being notified when the user enters a store's region 当用户进入商店区域时收到通知
  • dynamically recalculating the nearest N stores as the device moves 在设备移动时动态重新计算最近的N个商店

My previous answer was geared towards the first issue. 我以前的答案是针对第一个问题的。 Regarding the second issue, dynamically recalulating nearest N, the code in your didUpdateLocations will not be called unless you tell the location manager to startUpdatingLocation. 关于第二个问题,动态重新计算最接近的N,除非您告诉位置管理器startUpdatingLocation,否则不会调用didUpdateLocations中的代码。 Just off the top of my head: 就在我的头顶上:

// configure the location manager in AppDelegate:
// You will need to experiment with these two properties,
// you probably don't want to use kCLLocationAccuracyBestForNavigation. 
// Maybe kCLLocationAccuracyKilometer would be sufficient.
locmgr.distanceFilter = n
locmgr.desiredAccuracy = m
locmgr.pausesLocationUpdatesAutomatically = true
locmgr.startUpdatingLocation()



// this is the delegate that will receive the events due to locmgr.startUpdatingLocation
locationManager:didUpdateLocation {
    // Unless you have a specific need for it, I would refactor so that
    // you don't need self.PreviousTwentyStores:
    [self stopMonitoringStores];
    [self sortClosestStores];
    [self startMonitoringClosestStores];
}


locationManager:didEnterRegion {
    // you are in the region surrounding one of the stores.
}

Alternately, consider just setting a timer and waking the app every N seconds or minutes to recalculate the nearest stores. 另外,也可以考虑设置计时器并每N秒或每分钟唤醒一次应用,以重新计算最近的商店。

As I understand the various aspects of CoreLocation 据我了解CoreLocation的各个方面

startUpdatingLocation -> didUpdateLocations -> stopUpdatingLocation startUpdatingLocation-> didUpdateLocations-> stopUpdatingLocation

is (in one sense) entirely separate from: (在某种意义上)与以下内容完全分开:

startMonitoringForRegion -> didEnterRegion | startMonitoringForRegion-> didEnterRegion | didExitRegion -> stopMonitoringForRegion didExitRegion-> stopMonitoringForRegion

Additionally, startUpdatingLocation was never called so your didUpdateLocation was never called. 此外,从未调用过startUpdatingLocation,因此也从未调用过didUpdateLocation。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM