ios - 我是否错误地处理了位置更新?

标签 ios objective-c cllocationmanager ibeacon

目前我的位置代码都是单例的一部分。我很好奇这是否是导致我出现问题的原因。我将位置单例用作地理围栏区域和 iBeacon 的一部分。我正在测试的位置有多个 iBeacon,似乎有时进入信标区域会中断前一个区域的退出。我很好奇这是否正在发生,因为这是一个单例,如果我应该将其更改为应用程序委托(delegate)初始化以启动监视的标准类,并且应用程序将为发生的每个回调处理回调。我认为,因为它是一个单例,所以发生的第二个回调会在第一个回调尚未完成时停止。

您可以从下面的日志中看到我退出了地下室,它启动了一个定时事件以确保我真正退出了地下室(软件过滤器消除了 iBeacons 发生的快速退出/进入)。然后我走进我的起居室,它触发了另一个区域事件,但我们从未收到消息 didExitRegion:Basement logged out。

2014-04-25 15:35:22.757 [2761:707] Just Requested Background Time
2014-04-25 15:35:22.761 [2761:707] Basement
2014-04-25 15:35:22.767 [2761:707] Start Timed Event To See If Its A False Exit
2014-04-25 15:35:22.777 [2761:707] Just Requested Background Time
2014-04-25 15:35:22.778 [2761:707] Basement
2014-04-25 15:35:22.780 [2761:707] Start Timed Event To See If Its A False Exit
2014-04-25 15:35:23.751 [2761:707] Just Requested Background Time
2014-04-25 15:35:23.753 [2761:707] didEnterRegion: Living Room
2014-04-25 15:35:23.772 [2761:707] Just Requested Background Time
2014-04-25 15:35:23.774 [2761:707] didEnterRegion: Living Room
2014-04-25 15:35:24.270 [2761:707] Job ID Value
2014-04-25 15:35:24.272 [2761:707] 3208

nstimer 更改后的新日志:

2014-04-25 17:13:06.873 [3243:707] Just Requested Background Time
2014-04-25 17:13:06.875 [3243:707] Kitchen
2014-04-25 17:13:06.877 [3243:707] Start Timed Event To See If Its A False Exit
2014-04-25 17:13:06.884 [3243:707] Just Requested Background Time
2014-04-25 17:13:06.885 [3243:707] Kitchen
2014-04-25 17:13:06.886 [3243:707] Start Timed Event To See If Its A False Exit
2014-04-25 17:13:09.146 [3243:707] didExitRegion Basement
2014-04-25 17:13:09.149 [3243:707] Cancelled Exit Of Region: Basement
2014-04-25 17:13:09.881 [3243:707] Job ID Value
2014-04-25 17:13:09.883 [3243:707] 4040
2014-04-25 17:13:09.884 [3243:707] Connection Successful 
2014-04-25 17:13:10.878 [3243:707] Cancelled Exit Of Region: Kitchen
2014-04-25 17:13:10.889 [3243:707] Cancelled Exit Of Region: Kitchen

代码更新:

- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
    currentRegion = region;
    GeofenceObject *gObject = [[GeofenceObject alloc] init];
    gObject = [self getObjectForGeofence:region];

    //stop multiple notification deliveries
    if (notificationDelivered && ![gObject getIsBeacon])
    {
        notificationDelivered = NO;
        return;
    }

    BOOL alwaysNotify = [[NSUserDefaults standardUserDefaults] boolForKey:@"alwaysNotifyLocation"];
    if (![self checkWifi] && ![self checkWWLAN] && ![gObject getIsBeacon])
    {
        [self notifyNoNetwork:gObject forState:[NSNumber numberWithInt:1]];
        return;
    }

    if ((alwaysNotify && ![gObject getIsBeacon]))
    {
        [self notifyAlways:gObject forState:[NSNumber numberWithInt:1]];
        return;
    }

    BOOL isInBackground = NO;
    if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground)
    {
        isInBackground = YES;
    }

    NSTimer *timer = (NSTimer *)[self.timers objectForKey:[gObject getGeofenceName]];
    if (timer != nil)
    {
        [timer invalidate];
        [self.timers removeObjectForKey:[gObject getGeofenceName]];
    }

    if (isInBackground && [gObject getIsBeacon])
    {
        [self beginBackgroundTask];
        NSLog(@"%@", [@"didEnterRegion: " stringByAppendingString:[gObject getGeofenceName]]);
        [self didEnterRegion:region forObject:gObject];
        return;
    }

    if (isInBackground)
    {
        [self beginBackgroundTask];
        NSLog(@"%@",[@"didEnterRegion " stringByAppendingString:[gObject getGeofenceName]]);
        [self didEnterRegion:region forObject:gObject];
        return;
    }

    if ([gObject getIsBeacon])
    {
        NSLog(@"%@", [@"didEnterRegion: " stringByAppendingString:[gObject getGeofenceName]]);
        [self didEnterRegion:region forObject:gObject];
    }

    NSLog(@"%@",[@"didEnterRegion " stringByAppendingString:[gObject getGeofenceName]]);
    [self didEnterRegion:region forObject:gObject];
}

- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
{
    currentRegion = region;
    GeofenceObject *gObject = [[GeofenceObject alloc] init];
    gObject = [self getObjectForGeofence:region];

    //stop multiple notification deliveries
    if (notificationDelivered && ![gObject getIsBeacon])
    {
        notificationDelivered = NO;
        return;
    }

    BOOL alwaysNotify = [[NSUserDefaults standardUserDefaults] boolForKey:@"alwaysNotifyLocation"];
    if (![self checkWifi] && ![self checkWWLAN] && ![gObject getIsBeacon])
    {
        [self notifyNoNetwork:gObject forState:[NSNumber numberWithInt:0]];
        return;
    }

    if ((alwaysNotify && ![gObject getIsBeacon]))
    {
        [self notifyAlways:gObject forState:[NSNumber numberWithInt:0]];
        return;
    }

    BOOL isInBackground = NO;
    if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground)
    {
        isInBackground = YES;
    }

    if (isInBackground && [gObject getIsBeacon])
    {
        [self beginBackgroundTask];
        [gObject setJustExitedRegion:YES];
        [self replaceObjectWithUpdate:gObject];
        NSDictionary *info = [NSDictionary dictionaryWithObject:region forKey:@"region"];
        NSLog(@"%@", [gObject getGeofenceName]);
        NSLog(@"%@", @"Start Timed Event To See If Its A False Exit");
        [self.timers setObject:[NSTimer scheduledTimerWithTimeInterval:4.0f target:self selector:@selector(checkBackOnExit:) userInfo:info repeats:NO] forKey:[gObject getGeofenceName]];
        return;
    }

    if (isInBackground)
    {
        [self beginBackgroundTask];
        NSLog(@"%@",[@"didExitRegion " stringByAppendingString:[gObject getGeofenceName]]);
        [self didExitRegion:region forObject:gObject];
        return;
    }

    if ([gObject getIsBeacon])
    {
        [gObject setJustExitedRegion:YES];
        [self replaceObjectWithUpdate:gObject];
        NSDictionary *info = [NSDictionary dictionaryWithObject:region forKey:@"region"];
        NSLog(@"%@", [gObject getGeofenceName]);
        NSLog(@"%@", @"Start Timed Event To See If Its A False Exit");
        [self.timers setObject:[NSTimer scheduledTimerWithTimeInterval:4.0f target:self selector:@selector(checkBackOnExit:) userInfo:info repeats:NO] forKey:[gObject getGeofenceName]];
        return;
    }

    NSLog(@"%@",[@"didExitRegion " stringByAppendingString:[gObject getGeofenceName]]);
    [self didExitRegion:region forObject:gObject];
}

- (void)beginBackgroundTask
{
    NSLog(@"%@", @"Just Requested Background Time");
    bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
        NSLog(@"%@", @"Just Cancelled Background Time");
        [[UIApplication sharedApplication] endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    }];
}

- (void)checkBackOnExit:(NSTimer *)timer
{
    NSDictionary *info = [timer userInfo];
    CLRegion *region = [info objectForKey:@"region"];
    GeofenceObject *gObject = [[GeofenceObject alloc] init];
    gObject = [self getObjectForGeofence:region];
    if ([gObject getJustExitedRegion])
    {
        [self didExitRegion:region forObject:gObject];
        NSLog(@"%@",[@"didExitRegion " stringByAppendingString:[gObject getGeofenceName]]);
        [gObject setJustExitedRegion:NO];
        [self replaceObjectWithUpdate:gObject];
        [timer invalidate];
        [self.timers removeObjectForKey:[gObject getGeofenceName]];
        info = nil;
    }else
    {
        [timer invalidate];
        [self.timers removeObjectForKey:[gObject getGeofenceName]];
        NSLog(@"%@", [@"Cancelled Exit Of Region: " stringByAppendingString:[gObject getGeofenceName]]);
        info = nil;
        return;
    }
}

最佳答案

你的问题是这一行 -

[NSTimer scheduledTimerWithTimeInterval:4.0f target:self selector:@selector(checkBackOnExit:) userInfo:info repeats:NO];

您不会将从 scheduledTimerWithTimeInterval 返回的新 NSTimer 存储在任何地方,因此一旦方法退出,它就会被释放。您需要将 NSTimer 添加到属性中。由于您可能同时运行多个计时器,因此我建议使用 NSMutableDictionary

@property (retain,nonatomic)  NSMutableDictionary *timers;

在适当的地方初始化它(例如init)

self.timers=[[NSMutableDictionary alloc]init];

然后在 didExitRegion:

[self.timers addObject:[NSTimer scheduledTimerWithTimeInterval:4.0f target:self selector:@selector(checkBackOnExit:) userInfo:info repeats:NO] forKey:gObject.geoFenceName];

didEnterRegion:

NSTimer *timer=(NSTimer *)[self.timers objectForKey:gObject.geoFenceName]
if (timer != nil) {
    [timer invalidate];
    [self.timers removeObjectForKey:gObject.geoFenceName];
}

还有你的checkBackOnExit:方法

[timer invalidate];
[self.timers removeObjectForKey:gObject.geoFenceName];

关于ios - 我是否错误地处理了位置更新?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23302974/

相关文章:

ios - 如何从键盘打印格式化文本

ios - 全面替换已提交至苹果应用商店的应用

ios - 尝试显示其 View 不在窗口层次结构中(使用 segue 时)目标 - c

ios - CLBeaconRegion 没有从终止调用 didEnterRegion

ios - UIlabel不更新用户当前速度

ios - 区域/地理围栏监控 iOS 中区域的形状

ios - 使用 nspredicate 将 for 循环中的 NSArray 与给定输入进行比较

iphone - ***断言失败-[Scrapboom.iPhone.NewsFeedTableView _endCellAnimationsWithContext :],/SourceCache/UIKit/UIKit-2903.2/UITableView.m:1076

ios - 使用实例方法以编程方式添加 subview

objective-c - 如何获取 CalCalendarItem 的文件路径?