Swift UI Property Wrapper（プロパティラッパ） まとめ

## Property Wrapperとは？
Property Wrapperとは一言でいうと、**SwiftUIが変数の状態を自動で監視してくれる仕組み**のことです。
Property Wrapperを使うことで、複数のViewで変数を共有したり、変数が更新されるとViewを再描画してくれます。

## State

1.プロパティが更新可能になる。
2.プロパティが変更されるとビューも同時に更新される。

解説
通常SwiftUIのビューは、Structの為プロパティを更新することができません。しかし、@Stateを付けることで更新が可能になります。
また、@Stateをつけたプロパティは、SwiftUIによって監視されている為、変更があればビューを自動的に再描画してくれます。

## Binding

1.別のビュー同士の変数を紐づける。

解説
Bindingは少しややこしいので、子ビューから親ビューの変数の値を変更する簡単なコードを使って説明します。

まず以下のような親ビューAと子ビューBがあるとします。

```swift:sample
import SwiftUI

struct ParentView: View {
    @State var text = "初期の表示です。"
    @State var isShowView = false
    
    var body: some View {
        VStack {
            Text(text)
                .padding()
            Button("画面Bへ") {
                isShowView = true
            }
        }
        .sheet(isPresented: $isShowView) {
                ChildView(text: $text)
        }
    }
}

struct ChildView: View {
    @Binding var text: String
    
    var body: some View {
        Button("このボタンを押すとメッセージが変わります。") {
            text = "文字が変更されたよ！"
        }
    }
}

```

通常、Aの親ビューの中で定義された変数の値は、Bの子ビューから知ることができません。
しかし、@Bindingを使うことでそれが可能になります。
また、Bのビューで変数を変更することでAのビューの変数も変更されます。
上の例だと、ChildViewの中のボタンを押すことで、text変数に文字が入りAの画面に戻ると文字が変更されています。
つまり、@Bindingをつけることで親と子の双方向でのやり取りが可能になります。

## StateObject & ObservedObject

1.どちらもオブジェクトの状態を監視するプロパティラッパ
2.違いはビューのライフサイク

解説
StateObjectとObservedObjectの違いはビューのライフサイクです。

* StateObject：Viewに対してインスタンスが１つだけ生成される
* ObservedObject：Viewのライフサイクルに依存し、Viewの再描画でインスタンスを再生成する

## EnvironmentObject

1.アプリケーション全体から共通のオブジェクトにアクセスできる。

解説
ObserverdObjectなどは、値を子ビューに引き渡さなければ値を参照できないが、
EnvironmentObjectを付与すると、子ビューに引き渡さなくても共通の値を参照できるようになります。

例）以下のようなオブジェクトとViewがあったとします。
```swift:UserViewModel
class UserViewModel: ObservableObject {
    @Published var name = "ルフィ"
    @Published var age = 19
}

```
```swift:View1
struct View1: View {
    @EnvironmentObject var UserViewModel: UserViewModel
    var body: some View {
        VStack{
            Button(action: {
                UserViewModel.name = "ルフィ"
                UserViewModel.age = 19
            }){
                Text("ルフィを表示")
            }
            Text("\(UserViewModel.name)")
            Text("\(UserViewModel.age)")
        }
    }
}

```
```swift:View2
struct View2: View {
    @EnvironmentObject var UserViewModel: UserViewModel
    var body: some View {
        VStack{
            Button(action: {
                UserViewModel.name = "ゾロ"
                UserViewModel.age = 21
            }){
                Text("ゾロを表示")
            }
            Text("\(UserViewModel.name)")
            Text("\(UserViewModel.age)")
        }
    }
}

```
```swift:MainView
struct MainView: View {
    @EnvironmentObject var UserViewModel: UserViewModel
    var body: some View{
        VStack {
            View1()
            View2()
        }
        .environmentObject(UserViewModel)
    }
}
```
![Simulator Screen Recording - iPhone 14 - 2023-02-13 at 23.04.58.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3072069/e3794ef6-04bc-b463-9a09-d084e0d00cca.gif)

view1, view2で UserViewModelインスタンスを作成して、それぞれのビューでUserオブジェクトのname・ageプロパティを変更すると、変更するたびに全てのビューの値が更新されます。
上の例だとそれぞれのviewでボタンを押すと名前と年齢が変わるようにしました。

## おわりに
Property Wrapperは、まだまだ勉強中なので間違っていたらご指摘お願いいたします:bow_tone1: