LoginSignup
1
2

More than 1 year has passed since last update.

Swift UI Property Wrapper(プロパティラッパ) まとめ

Last updated at Posted at 2023-02-13

Property Wrapperとは?

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

State

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

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

Binding

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

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

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

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に対してインスタンスが1つだけ生成される
  • ObservedObject:Viewのライフサイクルに依存し、Viewの再描画でインスタンスを再生成する

EnvironmentObject

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

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

例)以下のようなオブジェクトとViewがあったとします。

UserViewModel
class UserViewModel: ObservableObject {
    @Published var name = "ルフィ"
    @Published var age = 19
}

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)")
        }
    }
}

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)")
        }
    }
}

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

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

おわりに

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

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2