Mapで位置情報を示し、ピンをたてる

#はじめに
超初心者でも簡単にMap機能が使えるように、その概要をざっくり理解してとりあえず動くものを作るまでの記録👍
Map機能を使ったことがなく、これから位置情報を扱うアプリを作ってみたいと言う方向けに超基本をチュートリアルとしてまとめました。

地図に位置情報を表示
おまけ　指定した場所にピンを置く

地図機能についてまずは簡単におさらいします。それが終わったら、セットアップを始めましょう。

#Map機能について知る
Swiftで使えるMKMapViewについて学んでいきましょう。
MapKitとは
アプリ内に地図または衛星画像を表示し、興味のある地点を位置情報として呼び出し、地図座標の目印情報を決定するSwiftのライブラリです。

#セットアップ
SwiftでMapKitを使う際には以下の２点が必要になります。
1. info.plistを選択
2.+を押して、Privacy-Location when in Use Usage Descriptionを選択し、そのよこのValueの欄に「位置情報を使用します」（文言はなんでもいい）と入力します。
3.Privacy-Location Always and When in Use Usage Descriptionも同様に選択し、同じ文言を書きます。


![67735127-2476-4E46-9429-DC5C16AC0754.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689115/b9addb95-8263-9243-655b-399b77d5ebac.jpeg)

こうすることで、ユーザーに位置情報の使用を求める準備ができる

#Storyboardの準備
では、早速始めてみましょう。
![1DE7137A-3B8C-4A14-BE0B-B2123AAE0E44.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689115/51e30e62-94f8-ef3e-ff09-9ef491deb4c5.jpeg)

ViewControllerにMapKitViewをのせ、四方を固定してオートレイアウトします。
これでStoryboardの準備は完了です。


#ユーザーに位置情報の使用の確認を促す
ユーザーに位置情報表示の許可を取り、取れなかった場合は許可をリクエストし、とれた場合は位置情報の表示を開始します。

```swift
    private func configureLocationServices() {
        //セキュリティ認証のステータス
        let status = CLLocationManager.authorizationStatus()
        //ユーザーの許可が取れなかった場合
        if status == .notDetermined {
            //許可をリクエスト
            locationManager.requestAlwaysAuthorization()
            //ユーザーの許可が取れた場合
        } else if status == .authorizedAlways || status == .authorizedWhenInUse {
　　　　　　　//ユーザーの位置情報の表示を開始
           beginLocationUpdates(locationManager: locationManager)
        }
    }
```
#ユーザーの位置情報の表示を開始

地図の精度と現在地をユーザーに報告する更新の生成を開始します。

```swift
    private func beginLocationUpdates(locationManager: CLLocationManager) {
        //マップがユーザーの場所を表示する
        mapView.showsUserLocation = true
        //アプリが受信したいレベルの精度を利用可能な最高レベルに設定
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        //ユーザーの現在地を報告する更新の生成を開始します。
        locationManager.startUpdatingLocation()
    }
```
#最新の位置情報の更新を取得して、ズームする
アプリを開いて最初に位置情報を表示する際に、設定した範囲に地図をズームさせます。

```swift
    //ユーザーが場所を変更するたびにアップデートされる(現在地の更新時に何かしたいとき）
extension MapPointViewController:CLLocationManagerDelegate{
    //新しい位置情報が利用可能になったことをdelegateに知らせる
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        print("最新の位置情報を取得")
        //latestLocationがnilの時を弾く
        guard let latestLocation = locations.first else { return }
        //もし、現在地がnilだったら（起動して最初の時）
        if currentCoordinate == nil {
            //設定した新しい領域の範囲までズームする
            zoomToLatestLocation(with: latestLocation.coordinate)
　　　　　　　//ピンを置くときに呼ばれる（②）
            addAnnotation()
        }
    
        currentCoordinate = latestLocation.coordinate
    }
```
#位置情報の更新
ユーザーの位置情報の変化を更新して、表示します。
ターミナルに場所が変更されたかどうかを表示するためにprint文を入れます。

```swift
    //アプリがlocationManagerを作成したとき、および承認ステータスが変更されたときに、delegateに承認ステータスを通知します。
    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
       print("場所が変更されました")
        //位置情報を常に許可している、またはアプリを使っている時だけ使用許可にしているとき
        if status == .authorizedAlways || status == .authorizedWhenInUse {
            //現在地の更新の表示を始める
            beginLocationUpdates(locationManager: manager)
        }
    }
}
```
#おまけ　指定した場所にピンを立ててみよう
geeksalon恵比寿校（35.64593086630865, 139.70462782640197）に照準を合わせて、ピンを立ててみましょう。

```swift
    private func addAnnotation(){
        //ピンを立てる
        let geeksalonAnnotation = MKPointAnnotation()
        //恵比寿教室の緯度軽度を入力
        geeksalonAnnotation.coordinate = CLLocationCoordinate2DMake(35.64593086630865, 139.70462782640197)
        //ピンのタイトル
        geeksalonAnnotation.title = "geeksalon"
        //ピンのサブタイトル
        geeksalonAnnotation.subtitle = "素敵な人がいっぱい"
        //mapViewにピンを追加する
        mapView.addAnnotation(geeksalonAnnotation)
    }
}
```
![C8437954-8D2A-4D7B-BF18-AB1F1E7B004F.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689115/a11f9992-f024-83b3-cf0e-12b768239a42.png)
　表示されました。


#まとめ
①ユーザーに位置情報の使用許可をとる
②info.plistで位置情報設定をする
③ユーザーに位置情報の使用の確認を促す
④ユーザーの場所を表示する
⑤場所と縮尺を設定してズームする
⑥位置情報の更新

```swift
import UIKit
import MapKit
//位置情報は（少なくとも日本では）個人情報保護の観点から、ユーザー許可を取る必要がある。
class MapPointViewController: UIViewController {
    
    private let locationManager = CLLocationManager()
    //現在の緯度経度の指定
    private var currentCoordinate: CLLocationCoordinate2D?

    @IBOutlet weak var mapView: MKMapView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        configureLocationServices()

    }
    
    private func configureLocationServices() {
        locationManager.delegate = self
        //セキュリティ認証のステータス
        let status = CLLocationManager.authorizationStatus()
        //ユーザーの許可が取れなかった場合
        if status == .notDetermined {
            //許可をリクエスト
            locationManager.requestAlwaysAuthorization()
            //ユーザーの許可が取れた場合
        } else if status == .authorizedAlways || status == .authorizedWhenInUse {
           beginLocationUpdates(locationManager: locationManager)
        }
    }
    
    private func beginLocationUpdates(locationManager: CLLocationManager) {
        //マップがユーザーの場所を表示する
        mapView.showsUserLocation = true
        //アプリが受信したいレベルの精度を利用可能な最高レベルに設定
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        //ユーザーの現在地を報告する更新の生成を開始します。
        locationManager.startUpdatingLocation()
    }
    
    private func zoomToLatestLocation(with coordinate: CLLocationCoordinate2D) {
        //場所と尺度を組み合わせてできるのがMKCoordinateRegion
        let zoomRegion = MKCoordinateRegion(center: coordinate, latitudinalMeters: 10000, longitudinalMeters: 10000)
        mapView.setRegion(zoomRegion, animated: true)
    }
    private func addAnnotation(){
        //ピンを立てる
        let geeksalonAnnotation = MKPointAnnotation()
        //恵比寿教室の緯度軽度を入力
        geeksalonAnnotation.coordinate = CLLocationCoordinate2DMake(35.64593086630865, 139.70462782640197)
        //ピンのタイトル
        geeksalonAnnotation.title = "geeksalon"
        //ピンのサブタイトル
        geeksalonAnnotation.subtitle = "素敵な人がいっぱい"
        //mapViewにピンを追加する
        mapView.addAnnotation(geeksalonAnnotation)
    }
}

extension MapPointViewController:CLLocationManagerDelegate{
    //新しい位置情報が利用可能になったことをdelegateに知らせる
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        print("最新の位置情報を取得")
        //latestLocationがnilの時を弾く
        guard let latestLocation = locations.first else { return }
        //もし、現在地がnilだったら（起動して最初の時）
        if currentCoordinate == nil {
            //設定した新しい領域の範囲までズームする
            zoomToLatestLocation(with: latestLocation.coordinate)
            addAnnotation()
        }
    
        currentCoordinate = latestLocation.coordinate
    }
    //アプリがlocationManagerを作成したとき、および承認ステータスが変更されたときに、delegateに承認ステータスを通知します。
    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
       print("場所が変更されました")
        //位置情報を常に許可している、またはアプリを使っている時だけ使用許可にしているとき
        if status == .authorizedAlways || status == .authorizedWhenInUse {
            //現在地の更新の表示を始める
            beginLocationUpdates(locationManager: manager)
        }
    }
}
```