dasukoの技術ブログ

現役エンジニアのブログです。

【SwiftUI】@Stateと@Bindingの関係

SwiftUIでのプロジェクトの作り方、導入についてはこちらで紹介しています。

dasuko.hatenadiary.jp

StateとBinding

SwiftUIのViewはstructなのでプロパティの値を変更できません。

View間でプロパティのやりとりをしたい場合はStateBindingを使います。

 

SwiftUIでは、親Viewで宣言したStateプロパティを子Viewに渡し、子Viewでそのプロパティ値を変更することができます。

これはStateプロパティが単なる値ではなく、ここで宣言された変数はSwiftUIフレームワークによってメモリ管理されます。

SwiftUIによって実値が管理される読み書きが可能なプロパティーラッパーという感じです。

プロパティの本来の値を直接参照したい場合はwrappedValueを参照します。

 

SwiftUIでは、Viewをbody内で定義しますが、StateプロパティやBindingプロパティの値が変更されると

SwiftUIは自動的にbody内を再構築します。

State

SwiftUIでStateプロパティの変数をViewに渡すには$をつけて渡します。

import SwiftUI

struct ContentView: View {
    @State private var text = ""
    
    var body: some View {
        TextField("Text", text: $text)
    }
}

 

Stateプロパティの値はこのように参照することも可能です

@State private var isPlaying: Bool = false

...

if isPlaying == true {
    Text("isPlaying")
}

Binding

Stateプロパティで宣言された値は、Viewに渡すときに$をつけてBindingプロパティとして渡します。

 

これにより、親Viewのプロパティのバインディングが作成されます。

こちらはAppleのドキュメンに載っているサンプルとほとんど同じですが、

クリックする度にボタンの画像が次のように変化します。

再生中ボタン<->停止ボタン

import SwiftUI

struct ContentView: View {
    @State private var isPlaying: Bool = false
    
    var body: some View {
        VStack {
            PlayButton(isPlaying: $isPlaying)
        }
    }
}

struct PlayButton: View {
    @Binding var isPlaying: Bool
    
    var body: some View {
        Button(action: {
            self.isPlaying.toggle()
        }, label: {
            Image(systemName: isPlaying ? "pause.circle" : "play.circle")
        })
    }
}

 

プレビューはこんな感じです。

gyazo.com

このサンプルではContentViewの子ViewであるPlayButtonの中でしかisPlayingを変更していませんが、

もちろんContentViewで値を変更した場合もPlayButtonに反映されます。

 

例えばこんな感じでContentViewでToggleも定義し、

ToggleでもisPlayingの値を変更できるようにしてみます。

 

import SwiftUI

struct ContentView: View {
    @State private var isPlaying: Bool = false
    
    var body: some View {
        VStack {
            Toggle("Play", isOn: $isPlaying)
                .padding(50)
            
            PlayButton(isPlaying: $isPlaying)
        }
    }
}

struct PlayButton: View {
    @Binding var isPlaying: Bool
    
    var body: some View {
        Button(action: {
            self.isPlaying.toggle()
        }, label: {
            Image(systemName: isPlaying ? "pause.circle" : "play.circle")
        })
    }
}

 

プレビューはこのようになり、PlayButtonにも値の変更が反映されているのがわかるかと思います。

gyazo.com

最後に

値が変更されたときにViewを自動的に再構築するSwiftUI最高すぎますね!!!

値を更新するときにViewの更新を気にする必要がないということなので、

ロジック部分の開発により注力できるようになるのかなと思います!

 

 

参考になったという方や、ここ間違っているよ!という方は

ぜひコメントしていただけると嬉しいです!!!!

 

SwiftUIを一から極めたいという人は本を買ってみるといいかも!

SwiftUIを本気でやろうとしていない人にはお勧めしません。

 

 

参考

Apple Developer Documentation