7/04/2014

Note about distanceFromLocation: of CLLocation

CLLocation
- (CLLocationDistance)distanceFromLocation:(const CLLocation *)location;

When argument is nil, this method returns -1.
There is no document about this behavior and no definition about -1.
(Maybe it means invalid distance. ex. CLLocationInvalidDistance = -1 in internal)


CLLocation *location = [[CLLocation alloc] initWithLatitude:37.785834 longitude:-122.406417];
CLLocation *nilLocation = nil;
CLLocationDistance distance;

// distance from nil to location
distance = [location distanceFromLocation:nilLocation];
NSLog(@"distance %f", distance);
// -1.000000

// message send to nil object, results is nil
distance = [nilLocation distanceFromLocation:location];
NSLog(@"distance %f", distance);
// -0.000000


CLLocation の distanceFromLocation: メソッドの引数に nil を渡すと-1が返ってくる。
この挙動はドキュメントには載っていなくて、-1 が何を意味するかも定義されてない。
定義は無いけどたぶん CLLocationInvalidDistance = -1 とか内部的にはなってるんじゃないかな。

Equivalence of CLRegion

To see how the management of CLRegion by CLLocationManager,
I wrote below codes.
I found that CLRegion(s) that have same identifier isEqual.

*1
{
    // different parameters, same identifiers
    CLCircularRegion *region1 = [[CLCircularRegion allocinitWithCenter:CLLocationCoordinate2DMake(1020)
                                                                  radius:30
                                                              identifier:@"test"];
    CLCircularRegion *region2 = [[CLCircularRegion allocinitWithCenter:CLLocationCoordinate2DMake(4050)
                                                                  radius:60
                                                              identifier:@"test"];
    NSLog(@"regions are equal = %d", [region1 isEqual:region2]);
    // regions are equal = 1
}
{
    // same parameters, different identifiers
    CLCircularRegion *region1 = [[CLCircularRegion allocinitWithCenter:CLLocationCoordinate2DMake(1020)
                                                                  radius:30
                                                              identifier:@"test"];
    CLCircularRegion *region2 = [[CLCircularRegion allocinitWithCenter:CLLocationCoordinate2DMake(1020)
                                                                  radius:30
                                                              identifier:@"tes"];
    NSLog(@"regions are equal = %d", [region1 isEqual:region2]);
    // regions are equal = 0
}


So codes that remove a region has same identifier from mutable array or set are below. See simple way.

*2
    // remove region with same identifier from array
    NSArray *regions;
    CLRegion *regionToRemove;

    NSMutableArray *mArray = regions.mutableCopy;
    // normal way
    for (CLRegion *region in regions) {
        if ([region.identifier isEqualToString:regionToRemove.identifier]) {
            [mArray removeObject:region];
        }
    }
    
    // simple way
    [mArray removeObject:regionToRemove];

Conversely you may need to be careful about this behavior in certain situation.


CLLocationManager による CLRegion の管理の仕方を見てもしやと思いテストコードを書いてみると、同じ identifier の CLRegion は isEqual という事が分かった。
*1

という事で、Mutableな配列やセットから同じ identifier の region を削除するには単にこう書けばいい。simple wayの方を参照。
*2

逆に言うと、Mutableな配列から region を削除する時はこの挙動を気を付けなければならないケースがあるかも知れない。

Behavior of the monitoring region by CLLocationManager

In document

- (void)startMonitoringForRegion:(CLRegion *)region
If an existing region with the same identifier is already being monitored by the application, the old region is replaced by the new one. The regions you add using this method are shared by all location manager objects in your application and stored in the monitoredRegions property.
CLLocationManager manage regions with not equivalence of instance but equivalence of identifier.
And it's surprise for me that sharing regions with instances.


ドキュメントによれば
同じ identifier の region の監視を開始すると、古いものが新しいもので置き換えられる。
インスタンスの同一性ではなく、identifier の同値性で管理されるらしい。
また、監視を開始した region はアプリ内の全ての CLLocationManager で共有されて monitoredRegions プロパティに保存される。
インスタンス間で監視中の region が共有されるのは意外だった。