iBeacons在监控2个或更多区域时发布

时间:2014-05-11 08:52:01

标签: ios iphone objective-c uitableview ibeacon

在我的iBeaconReceiver应用中,我试图监控更多的1个区域,并且我使用了此代码

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Initialize location manager and set ourselves as the delegate and beacons dictionary
    _beacons = [[NSMutableDictionary alloc] init];
    self.locationManager = [[CLLocationManager alloc] init];
    self.locationManager.delegate = self;

    self.myBeaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:[[NSUUID alloc] initWithUUIDString:@"6C1AA496-1653-403D-BD1E-7F630AA6F254"] major: 1 minor: 1 identifier: @"region1"];

    self.myBeaconRegion2 = [[CLBeaconRegion alloc] initWithProximityUUID:[[NSUUID alloc] initWithUUIDString:@"6C1AA496-1653-403D-BD1E-7F630AA6F254"] major: 1 minor: 2 identifier: @"region2"];

    NSLog(@"startMonitoring");
    // Tell location manager to start monitoring for the beacon region
    [self.locationManager startMonitoringForRegion:self.myBeaconRegion];
    [self.locationManager startMonitoringForRegion:self.myBeaconRegion2];

    _myBeaconRegion.notifyEntryStateOnDisplay = YES;
    _myBeaconRegion2.notifyEntryStateOnDisplay = YES;


    // Check if beacon monitoring is available for this device
    if (![CLLocationManager isMonitoringAvailableForClass:[CLBeaconRegion class]]){
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Monitoring not available" message:nil delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles: nil]; [alert show]; return;
    }

}

然后我开始测量信标

- (void)locationManager:(CLLocationManager*)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
{
    if(state == CLRegionStateInside)
    {
        if([region.identifier isEqualToString:@"region1"])
            [self.locationManager startRangingBeaconsInRegion:self.myBeaconRegion];
        else if ([region.identifier isEqualToString:@"region2"])
            [self.locationManager startRangingBeaconsInRegion:self.myBeaconRegion2];
    }
}

现在我的问题在于,我创建了一个简单的UITableView以这种方式显示设备范围内的信标

-(void)locationManager:(CLLocationManager*)manager
       didRangeBeacons:(NSArray*)beacons
              inRegion:(CLBeaconRegion*)region
{
    //NSLog(@"didRangeBeacons");
    [_beacons removeAllObjects];

    NSArray *immediateBeacons = [beacons filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"proximity = %d", CLProximityImmediate]];
    if([immediateBeacons count])
        [_beacons setObject:immediateBeacons forKey:[NSNumber numberWithInt:CLProximityImmediate]];

    NSArray *nearBeacons = [beacons filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"proximity = %d", CLProximityNear]];
    if([nearBeacons count])
        [_beacons setObject:nearBeacons forKey:[NSNumber numberWithInt:CLProximityNear]];

    NSArray *farBeacons = [beacons filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"proximity = %d", CLProximityFar]];
    if([farBeacons count])
        [_beacons setObject:farBeacons forKey:[NSNumber numberWithInt:CLProximityFar]];

    [self.tableView reloadData];

}

使用_beacons字典。 这是我的情景:

首先,我必须说我使用iPad作为iBeacon天线,可以选择region1region2进行广播。

  1. 开始播放region1,一切正常,我的UITableView充满了该灯塔UUID
  2. 停止播放region1,启动region2,一切正常,我的UITabelView现在向我显示region2 UUID
  3. 停止region2并返回广播region1UITableView为空!无法找到信标
  4. 停止region1并立即重启region2我的region2 UUID中会显示UITableView。从这一点开始,只有region2被我的应用程序监听, PLUS 我的UITableView颤抖(意思是它的生涩)!!!,好像每半秒重新加载一次所有UI(例如在第1点和第2点没有发生的事情)
  5. 我已经阅读了一些关于这个问题的线索,并且用户通过对每个区域使用不同的标识符来解决,但我认为我使用不同的标识符,所以我不明白问题出在哪里!看起来每当它进入region2时就会忘记region1

    谢谢是提前

3 个答案:

答案 0 :(得分:3)

问题是locationManager: didRangeBeacons: inRegion:方法会为您测距的每个区域独立调用。因此,当iOS在两个区域中提供有关信标的信息时, 每个区域的方法将每秒调用一次。

这是所显示代码的问题,因为行[_beacons removeAllObjects]将在每次回调开始时清除字典。考虑其中一个回调可以包含一个空的信标数组。在对两个区域进行测距时,呼叫的时间是不确定的。因此,您可能会获得一个带有信标列表的回调,显示它,然后在一小段时间内使用空beacons数组获得另一个回调,从而导致第一个数组永远不会显示。同样,当两个区域显示信标时,显示可能会闪烁,具体取决于回调的时间。

解决方法是在每次回调开始时不清除字典。相反,您必须维护一个不同的字典,其中包含每个信标最后一次出现的时间戳,并定期删除任何信标。在你的显示器几秒钟内没有看到。

答案 1 :(得分:0)

我遇到了类似的问题,在我看来,这是因为didExitRegion:的回调没有及时发生。如果没有致电didExitRegion:,那么我相信didEnterRegion:的调用永远不会发生,因此您无法获取任何数据。由于API仍然相当新,因此该主题的文档很少。

使用不同的UUID Proximity ID的解决方案是您建议的一个选项,尽管当Major / Minor应该足以区分时,必须这样做是令人沮丧的。 Beacons的文档在某种程度上支持单个“使用”应该使用单个UUID。因此,例如,一系列商店将使用UUID来识别公司,Major用于识别商店,而商店用于识别商店内的位置。

您是否在Radar中提交了错误?在这些事情涉及的地方,我会建议数量很重要。

答案 2 :(得分:0)

在iOS中测量信标时需要考虑以下几点:

  1. 对于你已定义的每个CLBeaconRegion(并称为startMonitoringForRegion),你将每秒获得一次回调didRangeBeacons,如davidGYoung所说。只要您位于当前正在监控的信标区域内,就会发生这种情况。
  2. 当您的信标信号消失时(通过移动到该区域之外或者只是关闭您的信标发射机,如上所述),您将继续获取didRangeBeacon回调约30秒,而iOS发现您不再在里面信标区域。我认为这是为了避免回调中令人讨厌的“抖动”(尽管它们仍然会发生!)。请注意,如果发生这种情况,您的didRangeBeacon回调当然会显示RSSI = 0.
  3. 一旦iOS确定您已真正退出信标区域,您将从locationManager获得didExitRegion回调。
  4. - >所以你可以看到只需打开/关闭你的发射器你就不会立即看到你的信标探测器在区域之间切换,而是你应该看到两个区域(一个RSSI = 0,一个RSSI非零)大约30秒

    在你的情况下,我相信davidGYoung再次正确地假设你的阵列每次被清除时都有问题。为了避免表示层问题,您应该对数组进行双重缓冲(一个用于检测到每个信标区域,另一个用于UI表视图的单独数组)。我在Zatar RDM iphone应用程序中完成了这项工作,它运行良好,已经过10多个同步信标测试,没有任何问题。