SwiftUIで位置情報を取得しているコードの解説

## はじめに
　SwiftUIで位置情報を取得した時に参考にさせていただいたコードを解説することで復習したり、より理解を深めたりしたいと思い、コード解説をしてQiitaに投稿することにしました。
　位置情報を取得したいけれどコードを読むのが苦手だなという方などのお役に立てれば幸いです。
　
**参考にさせていただいたサイト**
[【SwiftUI】CoreLocationの使い方 | 明日から本気出す](https://from2morrow.com/how-to-use-corelocation-with-swiftui/)
## 1. LocationViewModelのコード
まず、LocationViewModelのコードの解説をします。

### import

位置情報の取得にはCoreLocationを使うため、CoreLocationをimportします。

```SWIFT
import CoreLocation
```
### 権限の状態と位置情報の宣言

次に権限の状態と位置情報の宣言します。
@Publishedがわからなかったので調べると、@Publishedはビューの更新を行っていることがわかりました。
@Published属性を付けたプロパティがSwiftUIの監視対象となり、値が変更されると参照しているビューが再描画されるそうです。

```SWIFT
@Published var authorizationStatus: CLAuthorizationStatus
@Published var lastSeenLocation: CLLocation?
```

### 初期化

locationManager.desiredAccuracyで位置情報の精度を設定できます。
locationManager.pausesLocationUpdatesAutomaticallyは位置情報の自動更新の一時停止の設定で、一時停止にする場合はtrueにします。

locationManager.startUpdatingLocationで位置情報の更新をスタートできます。
スタート後、delegateに登録した自身のクラスの対応するメソッドにコールバックが発生します。

```SWIFT
override init() {
        locationManager = CLLocationManager()
        authorizationStatus = locationManager.authorizationStatus
        
        super.init()
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.allowsBackgroundLocationUpdates = true // バックグラウンド実行中も座標取得する場合、trueにする
        locationManager.pausesLocationUpdatesAutomatically = false
        locationManager.startUpdatingLocation()
    } 
```

### 権限の要求

requestPermissionでは、位置情報をアプリで使用する権限の要求をします。

```SWIFT
func requestPermission() {
        locationManager.requestWhenInUseAuthorization()
        locationManager.requestAlwaysAuthorization() // バックグラウンド実行中も座標取得する場合はこちら
    }
```

API呼び出しに応じ、自動的に以下のような画面が出てきます。
ここで、一時的に許可やアプリの使用中は許可、許可しないの3つから選ぶことができます。
ユーザーの選択状況などに依存して、表示されるかどうかが変わります。
※許可しないを選択すると二回目以降は表示されません。

<img src= https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2871987/0a342a6f-ca83-4270-f455-2b05655f194a.png width=50%>

### 権限の更新

権限の状況が更新された場合、コールバック呼び出しを受けることができます。
権限状態によってはAPI呼び出しが失敗するため、現状の権限を保持しておき、判定などに利用します。

```SWIFT
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
        authorizationStatus = manager.authorizationStatus
    }
```

### 位置情報の更新

スタートした後、座標情報の更新に応じてこのメソッドが呼び出されます。
ここで座標情報をプロパティに保持することで、画面描画など別の処理に使用できます。

```SWIFT
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        lastSeenLocation = locations.first
    }
```

## 2. ContentViewのコード
次にContentViewのコードの解説をします。

### EnvironmentObject
@EnvironmentObjectを使ってlocationViewModelクラスのインスタンスを共有します。
@EnvironmentObjectはObservableObjectプロトコルに準拠したクラスのインスタンスとViewを紐づける仕組みです。
@ObservedObjectと違って子Viewに順番に渡すのではなく、アプリケーション全体からアクセスすることができます。
```SWIFT
@EnvironmentObject var locationViewModel = LocationViewModel()
```
### UIの表示
ここで位置情報をアプリに表示させます。
位置情報はDouble型のため、String型に変更してテキストとして表示させています。
```SWIFT
Text("経度：" + String(coordinate?.longitude ?? 0))
Text("緯度：" + String(coordinate?.latitude ?? 0))
Text("高度：" + String(locationViewModel.lastSeenLocation?.altitude ?? 0))
Text("速度：" + String(locationViewModel.lastSeenLocation?.speed ?? 0))
```
### 緯度・経度
ここでは、coordinateに２次元の座標位置を入れることで、緯度と経度にアクセスしやすいようにしています。

```SWIFT
var coordinate: CLLocationCoordinate2D? {
    locationViewModel.lastSeenLocation?.coordinate
}
```
### 権限要求画面の表示
ここはボタンを設置して、位置情報の権限要求に移動します。
ボタンを押すとrequestPermissionに移動するため、権限を要求する画面が表示されます。
```SWIFT
Button(action: {
         locationViewModel.requestPermission()
               }) {
                     Text("位置情報の使用を許可する")
                   }
```



### 参考文献
[【SwiftUI】CoreLocationの使い方 | 明日から本気出す](https://from2morrow.com/how-to-use-corelocation-with-swiftui/)
[coreLocation | Apple Developer Documentation ](https://developer.apple.com/documentation/corelocation/cllocation)
[CLLocationCoordinate2D | Apple Developer Documentation ](https://developer.apple.com/documentation/corelocation/cllocationcoordinate2d)
[【SwiftUI】@EnvironmentObjectの使い方 ](https://capibara1969.com/3119/)
[[SwiftUI][Combine] @Published は、Publisher を提供する Property Wrapper ](https://software.small-desk.com/development/2021/02/17/swift-combine-atpublished-publisher/)