ある地点への接近を知らせる（CoreLocation::CLLocationManager.startMonitoringForRegion）

# 地理的領域の観測

## LocationManager準備

Info.plistのRequired device capabilitiesにlocation-services追加
Info.plistのInformation Property ListにNSLocationAlwaysUsageDescriptionを追加して、許可を求めるダイアログに表示する文字列を設定

```swift:ViewController.swift
import UIKit
import CoreLocation

class ViewController: UIViewController, CLLocationManagerDelegate {
    
    var myLocationManager: CLLocationManager!
```

## 領域観測許可取得

```swift:ViewController.swift
        super.viewDidLoad()
        
        if !CLLocationManager.isMonitoringAvailableForClass(CLCircularRegion) {
            return
        }
        
        let status = CLLocationManager.authorizationStatus()
        if status == CLAuthorizationStatus.Restricted || status == CLAuthorizationStatus.Denied {
            return
        }
        
        myLocationManager = CLLocationManager()
        myLocationManager.delegate = self
        
        if status == CLAuthorizationStatus.NotDetermined {
            myLocationManager.requestAlwaysAuthorization()
        }
        
        if !CLLocationManager.locationServicesEnabled() {
            return
        }
```

## バックグラウンド処理実行許可確認

Info.plistのInformation background modesにRequired background modesを追加
画面左のファイル一覧からプロジェクト（一番上のルート）を選択し、Capabilitiesタブ->Background ModesのLocation updatesをチェック

```swift:ViewController.swift
        if status == CLAuthorizationStatus.Restricted || status == CLAuthorizationStatus.Denied {
            return
        }
        
        if UIApplication.sharedApplication().backgroundRefreshStatus != UIBackgroundRefreshStatus.Available {
            return
        }
```

*アプリケーションが実行していないときに、ある領域の境界線を横切ると、アプリケーションはそのイベントを処理するためにバックグラウンドで起動されます。同様に、イベントが発生したときにアプリケーションが一時停止中の場合、アプリケーションは動作させられて、イベントを処理するために短い時間（約10秒）が割り当てられます。必要であればアプリケーションは、UIApplicationクラスのbeginBackgroundTaskWithExpirationHandler:メソッドを使用して、より長いバックグラウンド実行時間を要求することができます。*

## 地理的領域の作成・登録（iOS7.0~）

```swift:ViewController.swift
        if UIApplication.sharedApplication().backgroundRefreshStatus != UIBackgroundRefreshStatus.Available {
            return
        }
        
        let center = CLLocationCoordinate2DMake(35.0, 139.0)
        var radius = 3000000.0
        if radius > myLocationManager.maximumRegionMonitoringDistance {
            radius = myLocationManager.maximumRegionMonitoringDistance
        }
        let identifier = "YourUniqueIdentifier"
        let geoRegion = CLCircularRegion.init(center: center, radius: radius, identifier: identifier)
        geoRegion.notifyOnEntry = true
        geoRegion.notifyOnExit = true
        myLocationManager.startMonitoringForRegion(geoRegion)
        
        myLocationManager.requestStateForRegion(geoRegion)
        
    }
    
    func locationManager(manager: CLLocationManager, didDetermineState state: CLRegionState, forRegion region: CLRegion) {
        if state == CLRegionState.Inside {
            print("inside")
        } else {
            print("outside")
        }
    }
    
    func locationManager(manager: CLLocationManager, monitoringDidFailForRegion region: CLRegion?, withError error: NSError) {
        print("fail to monitor for region")
    }
```

*地理的領域の観測は、登録後すぐに開始されるが、イベントが生成されるのは、境界を横断したときだけ
領域の境界線を横断しないと、イベントが生成されてデリゲートに送信されない
ユーザが領域境界内にいるかどうか判断するには、CLLocationManagerクラスのrequestStateForRegion:メソッドを使う*

*領域は共有のシステムリソースであり、システム全体で利用可能な領域の総数は限られているので、Core Locationは、1つのアプリケーションで同時に観測できる領域の数を20に制限している
ユーザの位置が変わるにつれて、距離の遠くなった領域を削除し、ユーザの進路上で近づいている領域を追加し、ユーザの近隣の領域のみ登録する
領域を登録しようとしたときに空きがないと、位置情報マネージャはデリゲートのlocationManager:monitoringDidFailForRegion:withError:メソッドを呼び出して、エラーコードkCLErrorRegionMonitoringFailureを渡す*

## 境界横断イベントの処理

```swift:ViewController.swift
            print("outside")
        }
    }
    
    func locationManager(manager: CLLocationManager, didEnterRegion region: CLRegion) {
        print("enter")
    }
    
    func locationManager(manager: CLLocationManager, didExitRegion region: CLRegion) {
        print("exit")
    }
```

*システムは、ユーザが境界線付近を移動しているときに大量のイベントを立て続けに生成するのを防ぐため、システムで定義された緩衝距離を越えるまでは境界線の横断を報告しない*

*Simulatorで実行する場合は、XcodeのProduct->Scheme->Edit Scheme->Options->Default Locationで位置情報の初期値を設定しておくと良い*

## 参考

[位置情報とマッププログラミングガイド](https://developer.apple.com/jp/documentation/LocationAwarenessPG.pdf)
[CLLocationManager Class Reference](https://developer.apple.com/library/ios/documentation/CoreLocation/Reference/CLLocationManager_Class/index.html#//apple_ref/doc/uid/TP40007125)