【发布时间】:2016-05-11 15:29:36
【问题描述】:
我想在用户每次通过商店数组时检查商店,我有 20 多家商店,所以我编写了一个函数来查找离用户位置最近的 20 家商店并监控它们。 locationManager: didUpdateLocations 更新列表,我还将旧的 20 个监控区域替换为新的 20 个最近的商店位置。
问题是locationManager: didEnterRegion在用户进入区域时没有被定期调用。
我还注意到,当我检查 locationManager.monitoredRegions NSSet 时,由于某种原因,这些区域有误(我用 if 句子检查了它,所以它们可能是正确的并且更短?)。
如果有人可以检查我的代码并可能注意到我做错了什么,那真的会帮助我!
我的代码:
monitorLocationViewController.m(滚动查看完整代码):
-(void)getStoresArrays:(NSNotification*)notification
{
//Fetching "allStoresArray"(NSArray of all the stores sent from another class using NSNotificationCenter) and adding it to "allStores"(NSMutableArray)
NSDictionary *storesCategoriesArrays=[notification userInfo];
self.allStores=[storesCategoriesArrays objectForKey:@"allStoresArray"];
//Calling "locationChangeHandler" for monitoring
[self locationChangeHandler];
}
#pragma mark - CLLocationDelegate methods
//Being called when user's location updated
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
//If "allStores"(NSMutableArray) isn't nil - calling "locationChangeHandler" to update monitoring
if (self.allStores!=nil) {
[self locationChangeHandler];
}
}
//Being called when user enters a monitored region
-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
NSLog(@"Entered");
}
#pragma mark - Closest stores sorting methods
//Sorting closest stores to the user's location and adding the 20 closest store to "twentyClosestStores"(NSMutableArray)
-(void)sortClosestStores
{
//Sorting "allStores"(NSMutableArray) from the closest "Store" to the furthest.
[self.allStores sortUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) {
//Creating "location1"(CLLocation) and "location2"(CLLocation) and initializing each with "obj1"(id) and "obj2"(id) coordinates
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];
//Creating "dist1"(float) and setting its value to the distance between "location1"(CLLocation) and the user's location
float dist1 =[location1 distanceFromLocation:self.locationManager.location];
//Creating "dist2"(float) and setting its value to the distance between "location2"(CLLocation) and the user's location
float dist2 = [location2 distanceFromLocation:self.locationManager.location];
//If the distances are equal - the order will stay the same
if (dist1 == dist2) {
return NSOrderedSame;
}
else if (dist1 < dist2) { //If "dist1"(float) is smaller than "dist2"(float) - "dist2"(float) will be before "dist1" in the array
return NSOrderedAscending;
}
else { //else - "dist2"(float) will be before "dist1" in the array
return NSOrderedDescending;
}
}];
//If "twentyClosestStores"(NSMutableArray) is nil
if (self.twentyClosestStores==nil) {
//Initializing "twentyClosestStores"(NSMutableArray)
self.twentyClosestStores=[NSMutableArray array];
}
//If "previousTwentyStores"(NSMutableArray) is nil
if (self.previousTwentyStores==nil) {
//Initializing "previousTwentyStores"(NSMutableArray)
self.previousTwentyStores=[NSMutableArray array];
}
//Setting "previousTwentyStores"(NSMutableArray) to "twentyClosestStores"(NSMutableArray)
self.previousTwentyStores=self.twentyClosestStores;
//Cleaning (reInitializing) "twentyClosestStores"(NSMutableArray)
self.twentyClosestStores=[NSMutableArray array];
//Adding indexes 0-19 of "allStores"(NSMutableArray) (20 closest stores to the user's current location) to "twentyClosestStores"(NSMutableArray)
for (int i = 0; i < 20; i++) {
[self.twentyClosestStores addObject:[self.allStores objectAtIndex:i]];
}
}
#pragma mark - Start/stop monitoring methods
//For updating monitoring
-(void)locationChangeHandler
{
//If "allStores"(NSMutableArray) isn't nil
if (self.allStores!=nil) {
//Finding the 20 closest stores to he user's location and adding it to "twentyClosestStores"(NSMutableArray)
[self sortClosestStores];
//Stop monitoring "previousTwentyStores"(NSMutableArray) (20 closest stores before user's location updated)
[self stopMonitoringStores];
//Start monitoring "twentyClosestStores"(NSMutableArray)
[self startMonitoringClosestStores];
}
}
//Start monitoring "twentyClosestStores"(NSMutableArray)
-(void)startMonitoringClosestStores
{
//If monitoring isn't availible for "CLCircularRegion"
if (![CLLocationManager isMonitoringAvailableForClass:[CLCircularRegion class]]) {
NSLog(@"Monitoring is not available for CLCircularRegion class");
}
//Run on all "twentyClosestStores"(NSMutableArray)'s objects
for (Store *currentStore in self.twentyClosestStores) {
//Creating "region"(CLCircularRegion) and setting it to "currentStore"(Store)'s circular region
CLCircularRegion *region=[currentStore createCircularRegion];
//Start monitoring "region"(CLCircularRegion)
[self.locationManager startMonitoringForRegion:region];
}
}
//Stop monitoring "previousTwentyStores"(NSMutableArray) (20 closest stores before user's location updated)
-(void)stopMonitoringStores
{
//Run on all "previousTwentyStores"(NSMutableArray)'s objects
for (Store *currentStore in self.previousTwentyStores) {
//Creating "region"(CLCircularRegion) and setting it to "currentStore"(Store)'s circular region
CLCircularRegion *region=[currentStore createCircularRegion];
//Stop monitoring "region"(CLCircularRegion)
[self.locationManager stopMonitoringForRegion:region];
}
}
//Finding a store for region
-(Store*)storeForRegion:(CLCircularRegion*)region
{
//Creating "latitude"(CGFloat) and "longtitude"(CGFloat) and setting it to "region"(CLCircularRegion)'s center.latitude/longtitude
CGFloat latitude=region.center.latitude;
CGFloat longtitude=region.center.longitude;
//Run on all "allStores"(NSMutableArray)'s objects
for (Store *currentStore in self.allStores) {
//If "currentStore"(Store)'s latitude and longtitude is equal to "latitude"(CGFloat) and longtitude(CGFloat)
if (currentStore.geoPoint.latitude==latitude&¤tStore.geoPoint.longitude==longtitude) {
//Returning "currentStore"(Store)
return currentStore;
}
}
//Store not found - returning nil
NSLog(@"No store found for this region: %@",[region description]);
return nil;
}
Store.m:
//Creating and returning a "CLCircularRegion" object of the store
-(CLCircularRegion*)createCircularRegion
{
//Creating "region"(CLCircularRegion) and initializing it with current store information (self) and radios of 200m
CLCircularRegion *region=[[CLCircularRegion alloc] initWithCenter:self.geoPoint radius:200 identifier:self.identifier];
//Setting "region"(CLCircularRegion)'s notifyOnEntry to YES
region.notifyOnEntry=YES;
//Returning "region"(CLCircularRegion)
return region;
}
注意:委托方法正在被调用,即使是 didEnterRegion:,但由于某种原因并非总是如此。
解决了问题:
(我决定不使用区域监控,自己做)
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
[self checkIfNearStore]; //Not being called in background
}
-(void)checkIfNearStore
{
for (Store *currentStore in self.allStores) {
if ([currentStore.circularRegion containsCoordinate:self.locationManager.location.coordinate]&¤tStore.alreadySendNotification==NO) {
NSLog(@"Entered: %@",[[self storeForRegion:currentStore.circularRegion] address]);
currentStore.alreadySendNotification=YES;
[self.storesAlreadySentNotifications addObject:currentStore];
}
}
for (Store *currentStore in self.storesAlreadySentNotifications) {
if (![currentStore.circularRegion containsCoordinate:self.locationManager.location.coordinate]) {
currentStore.alreadySendNotification=NO;
}
}
}
非常感谢!
【问题讨论】:
-
请注意,Apple 文档声明添加 CLRegion 进行监控是异步完成的,您还可以通过实现委托方法来验证该区域是否已添加:- locationManager:didStartMonitoringForRegion:
-
@FS.O,您仍然没有考虑到添加区域是异步完成的。
-
@FS.O,如果您查看内联文档,您会看到 Apple 说:这是异步完成的,可能不会立即反映在受监控的区域中。这意味着当你添加一个区域时,它可能不会立即添加,而是异步操作完成时。
-
在我的回复中,我给了你很多思考。如果您有后续问题,请告诉我。不要忘记投票并让每个人确切地知道您如何在用例中解决问题(通过更新编辑您的问题)。这将帮助下一个遇到此问题的人。如果它解决了问题,请使用答案上的复选标记接受答案,但更重要的是通过更新您的问题让我们知道适合您的解决方案。这将鼓励其他人回答您未来的问题。
-
@TommieC。我会的,谢谢
标签: ios objective-c cocoa-touch cllocationmanager nsset