从iBeacon邻近控制视图

时间:2013-11-22 14:55:39

标签: ios core-location ibeacon

我正在玩Corelocation和iBeacons。我在进入和退出某个地区时会触发通知,而且我可以对我的信标等进行调整。这一切都很好。

然而,我陷入了混乱。我想在靠近特定信标时加载第二个视图,然后当我们离开那个信标时关闭该视图,冲洗并重复第二个信标。

我正在努力:

  • 如何停止触发视图更改,因为测距不会停止。如果我手动停止测距或使用bool来测试我是否已经在第二个视图中这是可以的但是看起来很乱。

  • 如果我离开信标,如何关闭视图。要做到这一点,我想我不能停止测距,否则我不知道我是否搬走了。

我的代码如下。

    - (void)viewDidLoad
{
    [super viewDidLoad];

}

- (void)viewDidAppear:(BOOL)animated {

    // Setup Beacon Manager
    self.locationManager = [[CLLocationManager alloc] init];
    self.locationManager.delegate = self;
    NSUUID *uuid = [[NSUUID alloc]initWithUUIDString:@"B9407F30-F5F8-466E-AFF9-25556B57FE6D"];
    self.beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:uuid identifier:@"Beacon Region"];
    [self.locationManager startMonitoringForRegion:self.beaconRegion];
    [self.locationManager requestStateForRegion:self.beaconRegion];
    self.beaconStatLabel.text = @"StartLocationServices";



    //check to see if this is the first time we've run the app
    if ([[NSUserDefaults standardUserDefaults] floatForKey:@"tBHasRun"] == 0) {
        [[NSUserDefaults standardUserDefaults] setInteger:1 forKey:@"tBHasRun"];  //set the time run to 1
        [self performSegueWithIdentifier:@"firstRunSegue" sender:self];
        self.beaconStatLabel.text = @"FIRST RUN"; //set the label text
    } else {
        self.beaconStatLabel.text = @"REPEAT RUN"; //set the label text
    }

}


    //Looking for and dealing with regions

- (void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region {
    //looking for a region means looking for a beacon or set of beacons that share a UUID
    [self.locationManager requestStateForRegion:self.beaconRegion];
}

- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
    //if we found a region we start ranging (looking for beaocns)
    [self.locationManager startRangingBeaconsInRegion:self.beaconRegion];
    self.regionState.text = @"Region Entered";

    //we'll also test sending a notification
    UILocalNotification *notification = [[UILocalNotification alloc] init];
    notification.alertBody = @"Welcome! Go upstairs, bring beer.";
    notification.soundName = UILocalNotificationDefaultSoundName;
    [[UIApplication sharedApplication] presentLocalNotificationNow:notification];
}

- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
    //we have left the region so we'll stop ranging
    [self.locationManager stopRangingBeaconsInRegion:self.beaconRegion];
    self.regionState.text = @"Region Exited";

    //we'll also test sending a notification
    UILocalNotification *notification = [[UILocalNotification alloc] init];
    notification.alertBody = @"Thankyou for coming.  For information on our next MeetUp check our MeetUp page.";
    notification.soundName = UILocalNotificationDefaultSoundName;
    [[UIApplication sharedApplication] presentLocalNotificationNow:notification];
}

    //dealing with individual beacons

- (void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region {
    //once beacons are ranged we enter this method

    //we'll grab and log the signal strength of the beacons
    for (int i = 0; i < [beacons count]; i++) {
        CLBeacon *singleBeacon = [[CLBeacon alloc]init];
        singleBeacon = [beacons objectAtIndex:i];
    }


    //we get the latest beacon in the array - the closest beacon (strongest signal)
    CLBeacon *beacon = [[CLBeacon alloc] init];
    beacon = [beacons lastObject];

    //update the info labels
    self.uuidLabel.text = beacon.proximityUUID.UUIDString;
    self.majorLabel.text = [NSString stringWithFormat:@"%@", beacon.major];
    self.minorLabel.text = [NSString stringWithFormat:@"%@", beacon.minor];

    //we store some information about that beacon
    NSNumber *beaconMajor = beacon.major;  //it's major (group) number
    NSNumber *beaconMinor = beacon.minor;  //it's minor (individual) number

    //we then call the manageBeacon method and pass through the minor, major, and proximity values
    [self manageBeaconWithMinor:beaconMinor AndMajor:beaconMajor AtRange:beacon.proximity];

}

- (void)manageBeaconWithMinor:(NSNumber *)minorNumber AndMajor:(NSNumber *)majorNumber AtRange:(CLProximity)proximity {
    //in this method we work out what do do based upon the beacon we are connected to and the range

    //for this test we'll look for the mint beacon and call a view
    if (([minorNumber floatValue] == 59204) && ([majorNumber floatValue] == 33995) && (proximity == CLProximityNear)) {
        //we are going to open up content
        [[tBGlobalStore sharedInstance]setInContentTrue];
        NSLog([[tBGlobalStore sharedInstance] getInContent] ? @"Yes" : @"No");
        //the beacon numbers match the beacon we are expecting so we'll call the next screen
        [self performSegueWithIdentifier:@"mainToContent" sender:self];
    }
}

来自控制台的一些其他信息,您可以看到它尝试多次调用该视图。

2013-11-22 15:24:56.487 testingBeacons [670:60b] --- 2013-11-22 15:24:56.489 testingBeacons [670:60b] ----- 2013-11-22 15:24:56.490 testingBeacons [670:60b] Beacon at: 2013-11-22 15:24:56.490 testingBeacons [670:60b] 0 2013-11-22 15:24:56.491 testingBeacons [670:60b]的RSSI为: 2013-11-22 15:24:56.492 testingBeacons [670:60b] -75 2013-11-22 15:24:56.492 testingBeacons [670:60b] ----- 2013-11-22 15:24:56.493 testingBeacons [670:60b] --- 2013-11-22 15:24:56.495 testingBeacons [670:60b]警告:尝试显示其视图不在窗口层次结构中! 2013-11-22 15:24:56.497 testingBeacons [670:60b] --- 2013-11-22 15:24:56.498 testingBeacons [670:60b] ----- 2013-11-22 15:24:56.498 testingBeacons [670:60b] Beacon at: 2013-11-22 15:24:56.499 testingBeacons [670:60b] 0 2013-11-22 15:24:56.499 testingBeacons [670:60b]的RSSI为: 2013-11-22 15:24:56.500 testingBeacons [670:60b] -75 2013-11-22 15:24:56.500 testingBeacons [670:60b] ----- 2013-11-22 15:24:56.501 testingBeacons [670:60b] --- 2013-11-22 15:24:57.487 testingBeacons [670:60b] --- 2013-11-22 15:24:57.489 testingBeacons [670:60b] ----- 2013-11-22 15:24:57.489 testingBeacons [670:60b] Beacon at: 2013-11-22 15:24:57.490 testingBeacons [670:60b] 0 2013-11-22 15:24:57.490 testingBeacons [670:60b]的RSSI为: 2013-11-22 15:24:57.491 testingBeacons [670:60b] -75 2013-11-22 15:24:57.491 testingBeacons [670:60b] ----- 2013-11-22 15:24:57.492 testingBeacons [670:60b] --- 2013-11-22 15:24:57.493 testingBeacons [670:60b]警告:尝试显示其视图不在窗口层次结构中! 2013-11-22 15:24:57.495 testingBeacons [670:60b] --- 2013-11-22 15:24:57.495 testingBeacons [670:60b] ----- 2013-11-22 15:24:57.496 testingBeacons [670:60b] Beacon at: 2013-11-22 15:24:57.496 testingBeacons [670:60b] 0 2013-11-22 15:24:57.497 testingBeacons [670:60b]的RSSI为: 2013-11-22 15:24:57.497 testingBeacons [670:60b] -75 2013-11-22 15:24:57.498 testingBeacons [670:60b] ----- 2013-11-22 15:24:57.499 testingBeacons [670:60b] --- 2013-11-22 15:24:57.500 testingBeacons [670:60b]警告:尝试在窗口层次结构中显示其视图! 2013-11-22 15:24:58.488 testingBeacons [670:60b] --- 2013-11-22 15:24:58.489 testingBeacons [670:60b] ----- 2013-11-22 15:24:58.490 testingBeacons [670:60b] Beacon at: 2013-11-22 15:24:58.490 testingBeacons [670:60b] 0 2013-11-22 15:24:58.491 testingBeacons [670:60b]的RSSI为: 2013-11-22 15:24:58.491 testingBeacons [670:60b] -76 2013-11-22 15:24:58.492 testingBeacons [670:60b] ----- 2013-11-22 15:24:58.492 testingBeacons [670:60b] --- 2013-11-22 15:24:58.493 testingBeacons [670:60b]警告:尝试显示其视图不在窗口层次结构中! 2013-11-22 15:24:58.494 testingBeacons [670:60b] --- 2013-11-22 15:24:58.495 testingBeacons [670:60b] ----- 2013-11-22 15:24:58.496 testingBeacons [670:60b] Beacon at: 2013-11-22 15:24:58.496 testingBeacons [670:60b] 0 2013-11-22 15:24:58.497 testingBeacons [670:60b]的RSSI为: 2013-11-22 15:24:58.497 testingBeacons [670:60b] -76 2013-11-22 15:24:58.498 testingBeacons [670:60b] ----- 2013-11-22 15:24:58.499 testingBeacons [670:60b] --- 2013-11-22 15:24:58.500 testingBeacons [670:60b]警告:尝试显示其视图不在窗口层次结构中! 2013-11-22 15:24:59.488 testingBeacons [670:60b] --- 2013-11-22 15:24:59.489 testingBeacons [670:60b] ----- 2013-11-22 15:24:59.489 testingBeacons [670:60b] Beacon at: 2013-11-22 15:24:59.490 testingBeacons [670:60b] 0 2013-11-22 15:24:59.490 testingBeacons [670:60b]的RSSI为: 2013-11-22 15:24:59.491 testingBeacons [670:60b] -75 2013-11-22 15:24:59.491 testingBeacons [670:60b] ----- 2013-11-22 15:24:59.492 testingBeacons [670:60b] --- 2013-11-22 15:24:59.493 testingBeacons [670:60b]警告:尝试在窗口层次结构中显示其视图! 2013-11-22 15:24:59.494 testingBeacons [670:60b] --- 2013-11-22 15:24:59.495 testingBeacons [670:60b] ----- 2013-11-22 15:24:59.495 testingBeacons [670:60b] Beacon at: 2013-11-22 15:24:59.496 testingBeacons [670:60b] 0 2013-11-22 15:24:59.496 testingBeacons [670:60b]的RSSI为: 2013-11-22 15:24:59.497 testingBeacons [670:60b] -75 2013-11-22 15:24:59.498 testingBeacons [670:60b] ----- 2013-11-22 15:24:59.498 testingBeacons [670:60b] --- 2013-11-22 15:24:59.500 testingBeacons [670:60b]警告:尝试显示其视图不在窗口层次结构中! 2013-11-22 15:25:00.487 testingBeacons [670:60b] --- 2013-11-22 15:25:00.488 testingBeacons [670:60b] ----- 2013-11-22 15:25:00.489 testingBeacons [670:60b] Beacon at: 2013-11-22 15:25:00.489 testingBeacons [670:60b] 0 2013-11-22 15:25:00.490 testingBeacons [670:60b]的RSSI为: 2013-11-22 15:25:00.490 testingBeacons [670:60b] -75 2013-11-22 15:25:00.491 testingBeacons [670:60b] ----- 2013-11-22 15:25:00.491 testingBeacons [670:60b] --- 2013-11-22 15:25:00.492 testingBeacons [670:60b]警告:尝试显示其视图不在窗口层次结构中! 2013-11-22 15:25:00.493 testingBeacons [670:60b] --- 2013-11-22 15:25:00.494 testingBeacons [670:60b] ----- 2013-11-22 15:25:00.494 testingBeacons [670:60b] Beacon at: 2013-11-22 15:25:00.495 testingBeacons [670:60b] 0 2013-11-22 15:25:00.495 testingBeacons [670:60b]的RSSI为: 2013-11-22 15:25:00.496 testingBeacons [670:60b] -75 2013-11-22 15:25:00.496 testingBeacons [670:60b] ----- 2013-11-22 15:25:00.497 testingBeacons [670:60b] --- 2013-11-22 15:25:00.498 testingBeacons [670:60b]警告:尝试显示其视图不在窗口层次结构中! 2013-11-22 15:25:01.488 testingBeacons [670:60b] --- 2013-11-22 15:25:01.489 testingBeacons [670:60b] ----- 2013-11-22 15:25:01.489 testingBeacons [670:60b] Beacon at: 2013-11-22 15:25:01.490 testingBeacons [670:60b] 0 2013-11-22 15:25:01.490 testingBeacons [670:60b]的RSSI为: 2013-11-22 15:25:01.491 testingBeacons [670:60b] -72 2013-11-22 15:25:01.492 testingBeacons [670:60b] ----- 2013-11-22 15:25:01.492 testingBeacons [670:60b] --- 2013-11-22 15:25:01.493 testingBeacons [670:60b]警告:尝试显示其视图不在窗口层次结构中! 2013-11-22 15:25:01.494 testingBeacons [670:60b] --- 2013-11-22 15:25:01.495 testingBeacons [670:60b] ----- 2013-11-22 15:25:01.495 testingBeacons [670:60b] Beacon at: 2013-11-22 15:25:01.496 testingBeacons [670:60b] 0 2013-11-22 15:25:01.497 testingBeacons [670:60b]的RSSI为: 2013-11-22 15:25:01.497 testingBeacons [670:60b] -72 2013-11-22 15:25:01.498 testingBeacons [670:60b] ----- 2013-11-22 15:25:01.498 testingBeacons [670:60b] --- 2013-11-22 15:25:01.499 testingBeacons [670:60b]警告:尝试在窗口层次结构中显示其视图!

2 个答案:

答案 0 :(得分:4)

我们遇到了类似的挑战。但是这两种解决方案都存在问题:Apple处理测距和接近度的方式存在“错误”,您将获得随机切换和didExitRegion调用。

见这里:

http://beekn.net/2013/11/ibeacon-tutorial-dealing-with-errors/

您的应用程序会随机调用didExitRegion,显然是一个错误,因为位置服务实际上可以完全关闭一秒左右。

我们通过在按下viewController后停止测距来处理viewController的想法,然后在用户关闭viewController后重新启动它。

  1. 后: [self performSegueWithIdentifier:@“mainToContent”sender:self];
  2. 添加:

    [self.locationManager stopRangingBeaconsInRegion:self.beaconRegion];

    1. 为了在用户关闭viewController后重新开始测距,请添加:
    2. //当推送OutsideViewController时,ViewWillAppear重新启动stopRanging - (void)viewWillAppear:(BOOL)animated {     [self.locationManager startRangingBeaconsInRegion:self.beaconRegion]; }

      注意:如果你想根据区域变化自动关闭viewController,你会遇到快速推拉的问题:你将推送一个viewController,然后它将快速关闭,打开,关闭......问题不在于代码,而是Apple API不能总是在想它所处的区域。

      可能的解决方案? “破解”可能是添加一个计数器:我们发现你将手机靠近信标,即使你没有移动手机也不会立即在近/立即切换之间切换信号实际上并没有改变。这是一个苹果“虫子”!但它只会这样做一两次。

      一个选项是添加一个计数器:相当于“只有在你触发事件时检测到区域变化三到四次”

      另一个选择是添加一个时间:“只有在区域发生变化4秒后才会根据区域变化触发事件”

      再次 - 问题不在于你会突然切换(推动VC或将其从堆栈中拉出来)因为你在“区域之间” - 问题是:

      一个。 Apple API无法始终正确判断您是立即/近/远并且会突然改变主意

      B中。 Apple有时会在不到一秒的时间内随意关闭位置服务,迫使您的应用重新进入某个地区并重新开始测距。

答案 1 :(得分:1)

didRangeBeacons:每个信标每秒调用一次,并且不跟踪您的接近变化。

CLLocationManagerDelegate Reference

我建议你做的是将信标跟踪封装在它自己负责的类中:

  1. 管理信标监控
  2. 保留特定iBeacons及其当前范围的哈希值。
  3. 调用一个协议方法,通知代理人(您的视图控制器),甚至NSNotificationCenter,当特定iBeacon的范围发生变化时(您知道因为您正在维护最近信标/邻近度的散列)。