CLLocationManager的生命周期,用于信标区域监控应用程序

时间:2015-11-11 09:50:32

标签: ios core-location ibeacon lifecycle region-monitoring

我注意到每当我再次启动应用程序并查看以下方法时,我得到的是返回的beaconRegion不是nill。这是如何工作的?

beaconRegion = [self.locationManager.monitoredRegions member:beaconRegion]; 
// for more context on how I use this please look at the code below

换句话说,iOS如何处理 CLLocationManager 的分配?每次应用程序被唤醒时它是否会对其进行反序列化,并以这种方式检索区域信息?

这是运行以下代码时Xcode调试器控制台的输出

2015-11-11 09:44:13.718 RegionMonitoringTest[239:15121] AppDelegate: creating new location manager object
2015-11-11 09:44:13.722 RegionMonitoringTest[239:15121] BeaconMonitoring class: in startRangingForBeacons, startupdatinglocation, range for my beacon
2015-11-11 09:44:13.724 RegionMonitoringTest[239:15121] Region already in list
2015-11-11 09:44:13.732 RegionMonitoringTest[239:15121] AppDelegate: Application did became active.
2015-11-11 09:44:13.762 RegionMonitoringTest[239:15121] BeaconMonitoring -> LocationManager: didFailWithError | Error: Error Domain=kCLErrorDomain Code=0 "(null)"
2015-11-11 09:44:13.762 RegionMonitoringTest[239:15121] Requesting to start ranging for beacons again.
2015-11-11 09:44:13.762 RegionMonitoringTest[239:15121] BeaconMonitoring class: in startRangingForBeacons, startupdatinglocation, range for my beacon
2015-11-11 09:44:13.767 RegionMonitoringTest[239:15121] Region already in list

下面我粘贴我用来测试它的源代码,它可能会有所帮助(它基于Apple提供的AirLocate示例):

#import "AppDelegate.h"
#define BEACON_REGION @"01020102-0102-0102-0102-010201020102"

@interface AppDelegate ()

@property (strong, nonatomic) CLLocationManager *locationManager;
@property (strong, nonatomic) NSMutableArray * monitoredRegions;

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.

    if ([launchOptions objectForKey:UIApplicationLaunchOptionsLocationKey]) {
        NSLog(@"AppDelegate: being woken up after entering region");
    }
    else{
        NSLog(@"AppDelegate: creating new location manager object");
        self.locationManager = [[CLLocationManager alloc] init];
        self.locationManager.pausesLocationUpdatesAutomatically = false;
        self.locationManager.allowsBackgroundLocationUpdates = true;
        self.locationManager.delegate = self;

        if([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
            [self.locationManager requestAlwaysAuthorization];
        }

        self.monitoredRegions = [[NSMutableArray alloc] initWithCapacity:10];

        [self startRangingForBeacons];
     }

    return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application {
    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
    NSLog(@"AppDelegate: will resign active");

}

- (void)applicationDidEnterBackground:(UIApplication *)application {
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.

    NSLog(@"AppDelegate: did enter background");
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
    // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
    //[self.bluetoothDataSync stopScanning];

    NSLog(@"AppDelegate: did enter foreground");
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
    NSLog(@"AppDelegate: Application did became active.");
}

- (void)applicationWillTerminate:(UIApplication *)application {
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
    //[[UIApplication sharedApplication] cancelAllLocalNotifications];
    NSLog(@"AppDelegate: App will terminate");
}

//////////////////////////////////////////////////

- (void) startRangingForBeacons{
    NSLog(@"BeaconMonitoring class: in startRangingForBeacons, startupdatinglocation, range for my beacon");
    [self startMonitoringForRegion:[[NSUUID alloc] initWithUUIDString:BEACON_REGION] :@"my-beaconregion"];
}


- (void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error {
    NSString * message = [NSString stringWithFormat:@"BeaconMonitoring -> LocationManager: monitoringDidFailForRegion | Error: %@, Region identifier: %@", error, region.identifier];

    NSLog(@"%@", message);
    NSLog(@"Requesting to start ranging for beacons again.");
    [self startRangingForBeacons];
}

- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
    NSString * message = [NSString stringWithFormat:@"BeaconMonitoring -> LocationManager: didFailWithError | Error: %@", error];
    NSLog(@"%@", message);
    NSLog(@"Requesting to start ranging for beacons again.");
    [self startRangingForBeacons];
}

- (void) startMonitoringForRegion:(NSUUID*)beaconUUID :(NSString*)regionIdentifier{
    CLBeaconRegion *beaconRegion = nil;

    beaconRegion = [self.locationManager.monitoredRegions member:beaconRegion];

    if(beaconRegion)
    {
        NSLog(@"Region already in list");
    }
    else{
        beaconRegion = [[CLBeaconRegion alloc] initWithProximityUUID:beaconUUID identifier:regionIdentifier];

        beaconRegion.notifyEntryStateOnDisplay = YES;
        beaconRegion.notifyOnEntry = YES;
        beaconRegion.notifyOnExit  = YES;

        [self.locationManager startMonitoringForRegion:beaconRegion];
    }

    [self.locationManager startRangingBeaconsInRegion:beaconRegion];
    [self.locationManager startUpdatingLocation];
    [self.monitoredRegions addObject:beaconRegion];
}

- (void) stopRangingForbeacons{
    NSLog(@"BeaconMonitoring: stopRangingForbeacons - Stops updating location");
    [self.locationManager stopUpdatingLocation];

    for (int i=0; i < [self.monitoredRegions count]; i++) {
        NSObject * object = [self.monitoredRegions objectAtIndex:i];

        if ([object isKindOfClass:[CLBeaconRegion class]]) {
            CLBeaconRegion * region = (CLBeaconRegion*)object;
            [self.locationManager stopMonitoringForRegion:region];
            [self.locationManager stopRangingBeaconsInRegion:region];
        }
        else{
        NSLog(@"BeaconMonitoring: unrecongized object in beacon region list");
        }
    }
}

- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
    if (![CLLocationManager locationServicesEnabled]) {
        NSLog(@"Couldn't turn on ranging: Location services are not enabled.");
    }

    if ([CLLocationManager authorizationStatus] != kCLAuthorizationStatusAuthorized) {
        NSLog(@"Couldn't turn on monitoring: Location services not authorised.");
    }
}


#pragma CLLocationManagerDelegate

-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {

    NSLog(@"BeaconMonitoring: did enter region, will now start ranging beacons in this region");
    [manager startRangingBeaconsInRegion:(CLBeaconRegion*)region];
    [self.locationManager startUpdatingLocation];
}


-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
    NSLog(@"BeaconMonitoring: did exit region, will now: stop ranging beacons in this region; stop updating locations; stop scanning for BLE");

    [manager stopRangingBeaconsInRegion:(CLBeaconRegion*)region];
    [self.locationManager stopUpdatingLocation];

    NSDictionary * notificationData = @{ @"value" : @"exitedRegion"};
    [[NSNotificationCenter defaultCenter] postNotificationName:@"dataUpdate" object:nil userInfo:notificationData];
}

- (void) locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
{
    NSString * message = @"CLRegionState: ";

    switch (state) {
        case CLRegionStateInside:
            message = @"CLRegionState: state inside";
            break;
        case CLRegionStateOutside:
            message = @"CLRegionState: state outside";
            break;
        case CLRegionStateUnknown:
            message = @"CLRegionState: state unknown";
            break;
        default:
            message = @"CLRegionState: default case";
            break;
    }

    NSLog(@"%@", message);
}

-(void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region {

    bool rangedBeacons = false;

    if ([beacons count]>0) {
        for (int i=0; i<[beacons count]; i++) {
            CLBeacon *beacon = [beacons objectAtIndex:i];
            if((beacon.major.intValue == 4) && (beacon.major.intValue == 8)){
                rangedBeacons = true;
            }
        }
    }

    if (rangedBeacons) {
        NSLog(@"Region identifier: %@", region.identifier);

        NSString * message = [NSString stringWithFormat:@"BeaconMonitoring: ranged a total of %lu, hence request scan start", (unsigned long)[beacons count]];
        NSLog(@"%@", message);
    }
}

1 个答案:

答案 0 :(得分:1)

由于位置管理器的监控工作即使应用程序未运行,例如,由于内存压力而终止或被应用程序切换器处的用户杀死,iOS需要保持区域应用程序监视器列表的位置在应用程序之外,您可以将monitoredRegions视为该列表的反映 - 而不是在对象被取消分配时消失的实例属性。

请注意,例如,如果您实例化多个位置管理器,它们都共享相同的监视列表 - 在操作系统级别的某个应用程序上存储的列表的直接结果。如果您在一个位置管理器中开始/停止监控某个区域,则会影响所有其他区域。

所有这些都适用于CLBeaconRegion,但也适用于&#34;常规&#34; CLCircularRegion - 因为它是监控功能,而不是特定于信标的功能。