【CoreLocation】位置情報を取得する

#iOS10で位置情報を取得するには
ヘルス系のアプリでは現在位置情報、マップ系のアプリではどこかしらの位置情報を取得して周辺地図を表示したいことがあります。
現在位置を取得する方法・概要を記しておきます。（自分のために）
Swiftの基本的な文法や記述に関して、詳しく知りたい方は「10歳になったらプログラミングをはじめよう[（iBooks Storeでみる）](https://geo.itunes.apple.com/jp/book/10suininattarapuroguraminguwohajimeyou/id1167914646?mt=11)」を参考にしていただければと思います。
Xcodeの基本的な使い方に関しては「Hello, world. Swift3[（iBooks Storeでみる）](https://geo.itunes.apple.com/jp/book/hello-world.-swift3/id1172722589?mt=11)」を参考にしてください。

##プロジェクトの概要
ビルド後、コンソールに位置情報（緯度:latitude, 経度:longitude）を出力する。
（Xcodeの機能を使って、シミュレータGPSが取得する位置データをシミュレートさせます）

##動作環境
Xcode8.1
iOS10.1
Swift3.0.1

##知っておくこと
###CoreLocationフレームワーク
iOS SDKには位置情報関連の機能がパッケージされた`CoreLocation フレームワーク`があります。`import`すると`CoreLocation`の機能がファイル内で使えるようになります。
プロジェクトナビゲータの`Linked Frameworks And Libraries`に、`CoreLocation`を追加しておきましょう。

###プライバシー情報の取得について
iOSアプリでは、ユーザの位置や連絡先、ヘルスなどプライバシーに関わる情報を取得する前に、ユーザから許可を得る必要があります。
許可を得るためには、`Info.plist`にその告知文を追加する必要があります。
Key: `Location When In Use Usage Description`
Value: `任意の文字列`（「このアプリは位置情報を取得します」的な内容）

###権限リクエストの種類
アプリがユーザから得られる認証にはいくつかの種類があります。
####`authorizedAlways`
常に許可する。
####`authorizedWhenInUse`
使用中だけ許可する。
####`denied`
許可しない。

##手順
大まかな流れは、以下のようになります。
1.フレームワークをインポート、マネージャ初期化
2.権限をリクエスト
3.マネージャの設定
4.プロトコルを採用して、デリゲートメソッドを実装

###1. フレームワークのインポートとマネージャ初期化
CoreLocationフレームワークをインポートします。

```ruby:ViewController.swift
import CoreLocation
```

位置情報の機能を管理する'CLLocationManager'クラスのインスタンス`locationManager`を`ViewController`クラスのメンバプロパティとして宣言しておきます。
`locationManager`オブジェクトの初期化は、`setupLocationManager()`メソッドを定義して行なっています。

```ruby:VeiwController.swift
class ViewController: UIViewController {

    var locationManager: CLLocationManager!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupLocationManager()
    }

    func setupLocationManager() {
        locationManager = CLLocationManager()
    }
}
```

###2. 権限をリクエスト
ユーザに対して、位置情報を取得する許可をリクエストします。
`setupLocationManager()`メソッド内で実装します。
今回は「アプリ使用中のみ許可を得る」ことにするので、インスタンスメソッド`requestWhenInUseAuthorization()`を使います。
ただし、`locationManager`オブジェクトが初期化に成功している場合のみ許可をリクエストします。

```ruby:VeiwController.swift
class ViewController: UIViewController {

    var locationManager: CLLocationManager!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupLocationManager()
    }

    func setupLocationManager() {
        locationManager = CLLocationManager()
        guard let locationManager = locationManager else { return }
        
        locationManager.requestWhenInUseAuthorization()
    }
}
```


###3. マネージャの設定
ユーザから「アプリ使用中の位置情報取得」の許可が得られた場合のみ、マネージャの設定を行います。
管理マネージャが位置情報を更新するペースを`distanceFilter`プロパティにメートル単位で設定します。
`startUpdatingLocation()`メソッドで、位置情報の取得を開始しています。

```ruby:VeiwController.swift
class ViewController: UIViewController {

    var locationManager: CLLocationManager!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupLocationManager()
    }

    func setupLocationManager() {
        locationManager = CLLocationManager()
        guard let locationManager = locationManager else { return }
        
        locationManager.requestWhenInUseAuthorization()

        let status = CLLocationManager.authorizationStatus()
        if status == .authorizedWhenInUse {
            locationManager.distanceFilter = 10
            locationManager.startUpdatingLocation()
        }
    }
}
```


###4. プロトコル採用とデリゲートメソッド実装
`ViewController`クラスに`CLLocationManagerDelegate`プロトコルを採用します。
`setupLocationManager()`メソッド内で、許可ステータスが`.authorizedWhenInUse`の場合に`ViewController`クラスが管理マネージャのデリゲート先になるようにします。

```ruby:VeiwController.swift
class ViewController: UIViewController, CLLocationManagerDelegate {

    var locationManager: CLLocationManager!
    
    override func viewDidLoad() {
        super.viewDidLoad()    
        setupLocationManager()
    }

    func setupLocationManager() {
        locationManager = CLLocationManager()
        guard let locationManager = locationManager else { return }
        locationManager.requestWhenInUseAuthorization()
        
        let status = CLLocationManager.authorizationStatus()
        if status == .authorizedWhenInUse {
            locationManager.delegate = self
            locationManager.distanceFilter = 10
            locationManager.startUpdatingLocation()
        }
    }
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        let location = locations.first
        let latitude = location?.coordinate.latitude
        let longitude = location?.coordinate.longitude
        
        print("latitude: \(latitude!)\nlongitude: \(longitude!)")        
    }
}
```

`locationManager(_: didUpdateLocations:)`デリゲートメソッドは、位置情報を取得・更新するたびに呼ばれます。

##ビルド
忘れずに`Info.plist`に宣言文のKey:Valueセットを追加しておいてください。
また、プロジェクトナビゲータの`Linked Frameworks And Libraries`に`CoreLocation`を追加していないと、位置情報は取得できません。
<img width="909" alt="スクリーンショット 2016-11-30 14.51.19.png" src="https://qiita-image-store.s3.amazonaws.com/0/70476/c03c08fd-6bf6-94ca-0c29-8a0f150fc48a.png">
シミュレータで位置情報を取得するには、エディタエリア下部のボタンからシミュレートできます。
ロケーションを変更するたびに、コンソールに経度・緯度が出力されます。