Chapter 09無料公開

【Part8】@State、@Bindingを理解しよう。~簡単なアプリを作って使い方を覚えよう~

Rikuto Sato
Rikuto Sato
2022.11.06に更新


このPartでは、@State@Bindingについて解説していきたいと思います。

変数とは?

まず、@State@Bidingを説明する前に、変数というのをしっかりと理解しておかなければならないので、変数からしっかりと説明していきたいと思います。

変数というのは、varがついている値のことです。イメージ的には値を入れる箱だと思ってください。
実は、前回、前々回のPartでも変数を書いています。DiceアプリではrandomNumberという変数を宣言して出目を入れいていました。モーダル遷移を実装する時には、isShowThirdViewという変数を宣言して、遷移するかどうかの値を入れていました。
というように、変数はプログラミングにとって最も重要です。

もし変数がなければ、「ボタンを押したらTextの文字を変える」というプログラムは書けません。
じゃあ、ボタンを押したらTextの文字を変えるというプログラムを見てみましょう。

struct ContentView: View {
    @State var str = "Hello, world!"
    
    var body: some View {
        VStack {
            Text(str)
                .padding()
            Button {
                str = "ハローワールド"
            } label: {
                Text("ボタン")
            }
        }
    }
}

まず、この画面はテキストとボタンがあるだけの画面です。
Textで、strを表示しています。str"Hello, world!"なので、画面には、「Hello, world!」と表示されます。
ボタンを押すと、str"ハローワールド"という文字列を代入(上書き)しています。それにより、画面に表示されているテキストが「ハローワールド」に変わります。
というように、Textの中身をstrという変数にしているため、ボタンを押したらTextの文字を変えることができるのです。strという変数がなかったらこのプログラムは実装できません。

図解すると以下のような感じです。

@Stateとは?

SwiftUI開発だと、@Stateがついている変数が出てきます。
では、@Stateをつけた変数は通常の変数と、異なる点が2点あります。

  1. 値が変わったら、Viewがリロードされます。
  2. Structの中で値を変更できます。
    この2つの仕様が追加されます。

1. 値が変わったらViewがリロードされる

@Stateがついた変数をボタンなどで変更すると、Viewがもう一度読み込まれます。
以下の図解は、ボタンを押したときに読み込まれる処理の順番を表した図解です。

もし、@Stateがついていなかったら、ボタンを押してもViewの再描画が行われないので、Textの文字は変わりません。

2. Structの中で値を変更できる

Swift言語のルール上、structの中で変数の変更はできません。(使うことはできる)
@Stateをついていない変数を書き換えようとすると、
Cannot assign to property: 'self' is immutableというエラーが起きます。

@Stateをつけると、このエラーは解消されます。

まとめると、@Stateは、structの中で値を変更できるようにし、変更するたびに再描画されるための修飾子です。

@Bindingとは?

次に@Bindingについて解説していきたいと思います。こちらは、プログラミング初心者にとっては、少し難しいと思うかもしれませんが、まずはここでは、そんなこともできるんだなぁ程度で覚えてください。
この入門講座では、繰り返し@Bindingを使っていくので、いずれ覚えられるかと思います。
@Bindingというのは、一言で言うと、View間でのデータの共有ができる修飾子です。
画面Aと画面Bがあるとすると、画面Bで画面Aの@Stateを変更したいときに@Bindingを使います。

一番簡単な例は、モーダル表示の画面を閉じる処理なので、前回のPart7の画面遷移を復習しながら@Bindingを使ってモーダル表示の画面を閉じる処理を行なっていきましょう。

適当にPart8とかでプロジェクトを作成してください。

@Bindingを使ってみる

  1. 画面Bを作る

    Part8を選択して、command + n



    ①SwiftUI Viewを選択
    ②Nextをクリック



    ①Save as:にBView.swiftと入力
    ②Createをクリック
    これで、BViewが作れました。

  2. 画面先の装飾
    BViewvar bodyの中を以下のように変更しましょう。ただ画面をオレンジ色にしているだけです。

    ZStack {
        Color(.orange)
    	.edgesIgnoringSafeArea(.all)
        Text("BView")
    	.font(.largeTitle)
    }
    
    変更する場所


  3. モーダル遷移処理作成
    ContentViewからBViewに遷移させたいので、ContentViewを以下のように変更してください。

    struct ContentView: View {
        @State var isShowBView = false
    
        var body: some View {
    	Button {
    	    isShowBView = true
    	} label: {
    	    Text("BViewへ")
    		.font(.largeTitle)
    	}
    	.sheet(isPresented: $isShowBView) {
    	    BView()
    	}
        }
    }
    
    変更する場所

    実行して確認してみると、ボタンを押したらBViewにモーダル遷移するはずです。


  4. 閉じるボタンを作る
    現状、下にスワイプすると画面を閉じれますが、ボタンでも閉じれるようにしましょう。
    まずはボタンを作成します。
    BView.swiftを開いてZStackの中を以下のようにVStackTextを囲ってButtonを追加しましょう。

    ZStack {
        Color(.orange)
    	.edgesIgnoringSafeArea(.all)
        VStack {
    	Text("BView")
    	    .font(.largeTitle)
    	Button {
    	} label: {
    	    Text("閉じる")
    	    .font(.largeTitle)
    	    .padding()
    	    .background(.green)
    	    .foregroundColor(.white)
    	    .cornerRadius(10)
    	}
        }
    }
    
    追記する場所

    これで、ボタンができました。


  5. @Bindingを宣言する
    画面を閉じるには、BViewを表示した処理の逆のことをしましょう。つまり、isShowBViewfalseにするということです。
    ですが、isShowBViewContentViewで宣言しているので、BViewでは使えません。
    そこで、@Bindingを使います。
    以下のコードをBViewの中で宣言してください。

    @Binding var isShowBView: Bool
    
    追記する場所


  6. プレビュー削除
    上記のように@Bindingを追加すると、プレビューを表示させるコードのところでエラーになります。
    今回はプレビューはもう必要ないので削除しましょう。


  7. @Bindingに値を渡す
    command + bを押すと、プロジェクトでエラーが発生しているかどうか確認できます。
    現状、ContentViewにエラーが発生しています。
    ContentView.swiftを確認してください。

    理由としては、BViewで宣言した@Bindingに値を渡していないからです。
    なので、@Bindingに値を渡しましょう。

    ①丸ぽちをクリック
    ②Fixをクリック
    そうすると、以下のように自動でBViewで宣言した@Bindingが表示されます。

    ここにContentViewisShowBViewを渡してあげます。
    以下のように記述してください。

    BView(isShowBView: $isShowBView)
    
    追記する場所


  8. 閉じる処理追加
    では、最後に閉じる処理を追記しましょう。
    ContentViewisShowBViewBViewに渡すことができたので、BViewでもisShowBViewが使えるようになりました。
    BViewButtonの中に以下のように処理を追記しましょう。

    Button {
        isShowBView = false
    } label: {
    
    追記する場所

    これでボタンを押したら画面が閉じるはずです。実行して確認してみましょう。

    これが@Bindingの使い方です。
    他のViewの値をいじりたい時は、このように@Bindingを使いましょう。この後のPartでも@Bindingを使っていくので、何回も何回も使って覚えていきましょう。

全てのコード

全てのコード
ContentView.swift
import SwiftUI

struct ContentView: View {
    @State var isShowBView = false
    
    var body: some View {
        Button {
            isShowBView = true
        } label: {
            Text("BViewへ")
                .font(.largeTitle)
        }
        .sheet(isPresented: $isShowBView) {
            BView(isShowBView: $isShowBView)
        }
    }
}
BView.swift
import SwiftUI

struct BView: View {
    @Binding var isShowBView: Bool
    
    var body: some View {
        ZStack {
            Color(.orange)
                .edgesIgnoringSafeArea(.all)
            VStack {
                Text("BView")
                    .font(.largeTitle)
                Button {
                    isShowBView = false
                } label: {
                    Text("閉じる")
                    .font(.largeTitle)
                    .padding()
                    .background(.green)
                    .foregroundColor(.white)
                    .cornerRadius(10)
                }
            }
        }
    }
}