9
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【SwiftUI】@Stateを理解したい

Last updated at Posted at 2023-03-31

はじめに

SwiftUIのStateについて学習したので備忘録とアウトプットのつもりで書いてみます。

作成するアプリ

ボタンをタップするとランダムに数字が切り替わるシンプルなものを作成してみたいと思います。
ezgif.com-video-to-gif.gif

とりあえず作ってみる

SwiftUIのState以外の部分の説明、解説は極力省いてしまいます。
まずは見た目を作っていきます。

struct ContentView: View {
    var body: some View {
        VStack {
            Text("\(0)")
                .font(.largeTitle)
                .padding()
            Button(action: {
            }) {
                Text("タップ")
                    .font(.largeTitle)
                    .frame(width: 200, height: 80, alignment: .center)
                    .border(.red)
            }
        }
    }
}

TextとButtonを縦に並べたいので、VStackを用います。
TextとButtonの見た目を適当に作成したら次はボタンをタップした時にTextの値を変更して更新します。

struct ContentView: View {
    
    private var number: Int = 0
    
    var body: some View {
        VStack {
            Text("\(number)")
                .font(.largeTitle)
                .padding()
            Button(action: {
                number = Int.random(in: 1..<10)
            }) {
                Text("タップ")
                    .font(.largeTitle)
                    .frame(width: 200, height: 80, alignment: .center)
                    .border(.red)
            }
        }
    }
}

一見、このコードではボタンをタップ(actionのクロージャが呼ばれる)するとnumber変数にランダムに値が格納されるように見えます。しかし、number = Int.random(in: 1..<10)の箇所でCannot assign to property: 'self' is immutableというエラーが出てしまいます。これは、プロパティは'self'がimmutable(変更できないもの)なので設定できないという意味です。
numberはvarで宣言されているので変更できそうですが、self(この場合はstruct ContentView)で作成されるインスタンスが変更を受け付けてくれません。
これを解決するためにStateを使いましょう。

Stateとは

ドキュメント

Stateを用いることによって
・値の更新を監視し、通知が来たら自動でViewを再描画する。
・struct内のプロパティを変更可能にする。
のメリットがあります。

先ほどのコードをもう一度見てみましょう。

struct ContentView: View {
    
    private var number: Int = 0
    
    var body: some View {
        VStack {
            Text("\(number)")
                .font(.largeTitle)
                .padding()
            Button(action: {
                number = Int.random(in: 1..<10)
            }) {
                Text("タップ")
                    .font(.largeTitle)
                    .frame(width: 200, height: 80, alignment: .center)
                    .border(.red)
            }
        }
    }
}

このコードで問題なのは、
・ボタンをタップし、numberに値が格納されても誰もそれを監視しておらず、Viewの再描画がされずにタップのタイミングでTextが更新されないということ。
・struct内のプロパティの変更が不可であること。
であるため、Stateを使って解決します。

@ Stateをnumber変数につけます。

struct ContentView: View {
    
    @State private var number: Int = 0
    
    var body: some View {
        VStack {
            Text("\(number)")
                .font(.largeTitle)
                .padding()
            Button(action: {
                number = Int.random(in: 1..<10)
            }) {
                Text("タップ")
                    .font(.largeTitle)
                    .frame(width: 200, height: 80, alignment: .center)
                    .border(.red)
            }
        }
    }
}

これによって、ボタンタップ後にnumberに新しく値が格納され、それをStateによって監視しているのでViewが再描画され新しい値が反映されます。

Property Wrapper(プロパティラッパー)

プロパティラッパーとは、プロパティに対する操作や処理をカプセル化して定義することでキーワードを追加するだけで任意の動作や挙動を行わせることができるデータ構造です。
すでに定義されている@ Stateはプロパティラッパーの一つです。
前述の通り、@ Stateはプロパティの値の変更を監視し、Viewを再描画してくれることとプロパティの変更を可能にしてくれる特徴を持ちます。
@ Bindingや@ Environmentなど他にもたくさんあるようです。そのうち書いてみたいなと思います。

おわりに

SwiftUI学習始めたばかりなので、間違ってる点がありましたらTwitterまたはコメントで"やさしく"教えてくださいませ。

9
4
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
9
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?