1

アプリを再起動して次のメソッドを見るたびに、返された 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);
    }
}
4

1 に答える 1

1

Location Manager の監視は、アプリが実行されていない場合でも機能するため (たとえば、メモリ不足のために終了したり、アプリ スイッチャーでユーザーによって強制終了されたりした場合)、iOS は、アプリが監視するリージョンのリストをアプリの外部のどこかに保持する必要があります。monitoredRegionsオブジェクトの割り当てが解除されると消えるインスタンス プロパティではなく、そのリストの反映と考えてください。

たとえば、複数のロケーション マネージャーをインスタンス化する場合、それらはすべて同じ監視リストを共有することに注意してください。これは、リストがアプリごとに OS レベルのどこかに格納されていることの直接的な結果です。1 つのロケーション マネージャーでリージョンの監視を開始/停止すると、他のすべての場所に影響します。

これはすべて に適用されますがCLBeaconRegion、「通常」にも適用されます。これCLCircularRegionは監視の機能であり、ビーコン固有のものではないためです。

于 2015-11-11T10:26:02.740 に答える