i m working on estimote beacon.

I try to present a ViewController when i m in switch Case "immediate". But when i the view is loaded, i have a warning :

2014-03-13 02:44:26.017 ProximityDemo[856:60b] Warning: Attempt to present on whose view is not in the window hierarchy!

Why ? I think the presentView Method is still working while i m on the new view.

Also when i m on the new View , i would like to pop to old view when i m in Case "Near"

I Think i have to implement all the the code in the new ViewController ? (presentProductViewController) Is there a way to have all the proximity/distance controll in only one Controller ?

Here is my code :

ESTViewController :

#import "ESTViewController.h"
#import <ESTBeaconManager.h>
#import "PresentProductViewController.h"

@interface ESTViewController () <ESTBeaconManagerDelegate>

@property (nonatomic, strong) ESTBeaconManager* beaconManager;
@property (nonatomic, strong) ESTBeacon* selectedBeacon;

@end

@implementation ESTViewController

- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.

/////////////////////////////////////////////////////////////
// setup Estimote beacon manager

// craete manager instance
self.beaconManager = [[ESTBeaconManager alloc] init];
self.beaconManager.delegate = self;
self.beaconManager.avoidUnknownStateBeacons = YES;

// create sample region object (you can additionaly pass major / minor values)
ESTBeaconRegion* region = [[ESTBeaconRegion alloc] initWithProximityUUID:ESTIMOTE_IOSBEACON_PROXIMITY_UUID
                                                              identifier:@"EstimoteSampleRegion"];

// start looking for estimote beacons in region
// when beacon ranged beaconManager:didRangeBeacons:inRegion: invoked
[self.beaconManager startRangingBeaconsInRegion:region];



}

-(void)beaconManager:(ESTBeaconManager *)manager
 didRangeBeacons:(NSArray *)beacons
        inRegion:(ESTBeaconRegion *)region
{
if([beacons count] > 0)
{

    if(!self.selectedBeacon)
    {
        // initialy pick closest beacon
        self.selectedBeacon = [beacons objectAtIndex:0];
    }
    else
    {
        for (ESTBeacon* cBeacon in beacons)
        {
            // update beacon it same as selected initially
            if([self.selectedBeacon.major unsignedShortValue] == [cBeacon.major unsignedShortValue] &&
               [self.selectedBeacon.minor unsignedShortValue] == [cBeacon.minor unsignedShortValue])
            {
                self.selectedBeacon = cBeacon;
            }
        }
    }



    // beacon array is sorted based on distance
    // closest beacon is the first one

    NSString* labelText = [NSString stringWithFormat:
                           @"Major: %i, Minor: %i\nRegion: ",
                           [self.selectedBeacon.major unsignedShortValue],
                           [self.selectedBeacon.minor unsignedShortValue]];

    // calculate and set new y position
    switch (self.selectedBeacon.proximity)
    {
        case CLProximityUnknown:
        {
            labelText = [labelText stringByAppendingString: @"Unknown"];
            break;
        }
        case CLProximityImmediate:
        {
            labelText = [labelText stringByAppendingString: @"Immediate"];

            PresentProductViewController *showViewController = [[PresentProductViewController alloc] initWithNibName:@"PresentProductViewController" bundle:nil];

            [self presentViewController:showViewController animated:YES completion:nil];

            break;
        }
        case CLProximityNear:
        {
            labelText = [labelText stringByAppendingString: @"Near"];
            break;

            //[self.navigationController popToRootViewControllerAnimated:YES];
            //ESTViewController *initViewController = [[ESTViewController alloc]init];
            //[self presentViewController:initViewController animated:YES completion:nil];
        }
        case CLProximityFar:
        {
            labelText = [labelText stringByAppendingString: @"Far"];
            break;
        }

        default:
            break;
    }

    self.distanceLabel.text = labelText;
}
}

- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}

@end

PresentProductViewController :

#import "PresentProductViewController.h"
#import <ESTBeaconManager.h>
#import "ESTViewController.h"

@interface PresentProductViewController () <ESTBeaconManagerDelegate>

@property (nonatomic, strong) ESTBeaconManager* beaconManager;
@property (nonatomic, strong) ESTBeacon* selectedBeacon;

@end

@implementation PresentProductViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
    // Custom initialization
}
return self;
}

- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
[self.activityIndicator startAnimating];

/////////////////////////////////////////////////////////////
// setup Estimote beacon manager

// craete manager instance
self.beaconManager = [[ESTBeaconManager alloc] init];
self.beaconManager.delegate = self;
self.beaconManager.avoidUnknownStateBeacons = YES;

// create sample region object (you can additionaly pass major / minor values)
ESTBeaconRegion* region = [[ESTBeaconRegion alloc] initWithProximityUUID:ESTIMOTE_IOSBEACON_PROXIMITY_UUID
                                                              identifier:@"EstimoteSampleRegion"];

// start looking for estimote beacons in region
// when beacon ranged beaconManager:didRangeBeacons:inRegion: invoked
[self.beaconManager startRangingBeaconsInRegion:region];


}

-(void)beaconManager:(ESTBeaconManager *)manager
 didRangeBeacons:(NSArray *)beacons
        inRegion:(ESTBeaconRegion *)region
{
if([beacons count] > 0)
{

    if(!self.selectedBeacon)
    {
        // initialy pick closest beacon
        self.selectedBeacon = [beacons objectAtIndex:0];
    }
    else
    {
        for (ESTBeacon* cBeacon in beacons)
        {
            // update beacon it same as selected initially
            if([self.selectedBeacon.major unsignedShortValue] == [cBeacon.major unsignedShortValue] &&
               [self.selectedBeacon.minor unsignedShortValue] == [cBeacon.minor unsignedShortValue])
            {
                self.selectedBeacon = cBeacon;
            }
        }
    }



    // beacon array is sorted based on distance
    // closest beacon is the first one

    self.labelText.text = [NSString stringWithFormat:
                           @"Major: %i, Minor: %i\nRegion: ",
                           [self.selectedBeacon.major unsignedShortValue],
                           [self.selectedBeacon.minor unsignedShortValue]];

    // calculate and set new y position
    switch (self.selectedBeacon.proximity)
    {
        case CLProximityUnknown:
        {
            self.labelText.text = [self.labelText.text stringByAppendingString: @"Unknown"];
            break;
        }
        case CLProximityImmediate:
        {
            self.labelText.text = [self.labelText.text stringByAppendingString: @"Immediate"];
            break;
        }
        case CLProximityNear:
        {
            self.labelText.text = [self.labelText.text stringByAppendingString: @"Near"];
            break;

            //UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:@"Main.storyboard" bundle:nil];
            //UIViewController *initViewController = [storyBoard instantiateInitialViewController];

            //[self.navigationController pushViewController:initViewController animated:YES];

            //ESTViewController *initViewController = [[ESTViewController alloc]init];
            //[self presentViewController:initViewController animated:YES completion:nil];

            //[self.navigationController popToRootViewControllerAnimated:YES];

        }
        case CLProximityFar:
        {
            self.labelText.text = [self.labelText.text stringByAppendingString: @"Far"];
            break;
        }

        default:
            break;
    }

}
}

-(void)viewDidDisappear:(BOOL)animated
{
[self.activityIndicator stopAnimating];
}

- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}

@end

I m sure i m doing wrong. Thanks for your help.

有帮助吗?

解决方案

The ESTBeaconManager is probably continuously delivering the latest changes via didRangeBeacons:inRegion even when you have presented PresentProductViewController. I think the following is what happens:

  1. ESTViewController's didRangeBeacons:inRegion is called with a non-empty array of beacons.
  2. The proximity property of the selected beacons is CLProximityImmediate, and PresentProductViewController is presented modally.
  3. While being the presenting (not presented), viewcontroller, ESTViewController's didRangeBeacons:inRegion is called with new changes. Again, a beacon has proximity immediate, and a new instance of PresentProductViewController is presented modally.

From ViewController Programming Guide

Any view controller object can present a single view controller at a time.

If the assumption outlined above is correct, you are trying to present multiple viewcontrollers modally at the same time, which is not a valid action. You could try to stop ranging for beacons when the view disappears, and then start ranging again when it appears. This will prevent the beacon manager from notifying ESTViewController of changes while it is not in a position to present viewcontrollers. Override viewWillDisappear and viewWillAppear methods to achieve this:

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    [self.beaconManager stopRangingBeaconsInRegion:region];
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [self.beaconManager startRangingBeaconsInRegion:region];
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top