Swift・iOS

Swiftを中心に学んだことを記録に残すブログです。技術に関係ない記事もたまに書いています。

【SwiftUI】@Stateはどのような時に使うのか説明してみた

■@Stateとは

"A property wrapper type that can read and write a value managed by SwiftUI."

※引用:Apple Developer Documentation

「SwiftUIによって管理される値を読み書きできるプロパティラッパータイプ」とのことです。

 

正直、上記ページを読んでもすぐに理解できませんでした。。以下サンプルコードを使いながら、どのような場面で使用するのか説明してみたいと思います。

 

■Buttonのサンプルコードを用いて@Stateを説明

1.ボタンを表示するコードを実装

まず、Buttonを表示するだけのサンプルを用意します。

import SwiftUI

struct ContentView: View {
    var buttonTitle = "Button sample"
    
    var body: some View {
        VStack {
            Button(action: {}) {
                Text("\(buttonTitle)")
                    .frame(width: 200, height: 70, alignment: .center)
                    .foregroundColor(Color.white)
                    .background(Color.blue)
                    .cornerRadius(10, antialiased: true)
            }
        }
    }
}

上記コードを実行すると以下のようなボタンが表示されます。

f:id:hfoasi8fje3:20201012221929p:plain

 

2.ボタンを選択したときの挙動を追加・変更する

次に、ボタンをタップした時の動作を追加してみます。

今回はボタンをタップするとボタンのタイトルが変更されるようにします。

「追加」、「変更」と記載した箇所を実装してみてください。

import SwiftUI

struct ContentView: View {
    // 追加
    var buttonTitle = "Button sample"
    
    var body: some View {
        VStack {
            Button(action: {
                // 追加
                self.buttonTitle = "Button tapped!"
            }) {
                // 変更
                Text("\(buttonTitle)")
                    .frame(width: 200, height: 70, alignment: .center)
                    .foregroundColor(Color.white)
                    .background(Color.blue)
                    .cornerRadius(10, antialiased: true)
            }
        }
    }
}

 

しかし、上記コードを実行しようとすると「Cannot assign to property: 'self' is immutable」エラーとなり実行できません。

確かに、(SwiftUIに関係なく)structに定義された変数buttonTitleを変更することはできません。mutatingを使えばbuttonTitleを変更することができるようになります。

※参考:Swiftのmutatingキーワードについて - Qiita

 

ただし、今回は「structに定義された変数buttonTitleを変更する」だけではなく、「buttonTitleの値が変更されたらButtonの表示も変更する」必要があります。そのため、mutatingでは要件を満たすことができません。

 

3.@Stateを追加

そこで@Stateの出番です。以下のように@Stateを追加すると、structに定義された変数buttonTitleを変更することができ、また、値が変更されるとViewを再描画するためボタンの表示も変更することができます。

import SwiftUI

struct ContentView: View {
    // @Stateを追加
    @State var buttonTitle = "Button sample"
    
    var body: some View {
        VStack {
            Button(action: {
                self.buttonTitle = "Button tapped!"
            }) {
                Text("\(buttonTitle)")
                    .frame(width: 200, height: 70, alignment: .center)
                    .foregroundColor(Color.white)
                    .background(Color.blue)
                    .cornerRadius(10, antialiased: true)
            }
        }
    }
}

@Stateによってエラーが解消され、ボタンを選択すると以下のような表示に変更されるようになりました。

f:id:hfoasi8fje3:20201012220412p:plain

 

■参考リンク

Apple Developer Documentation

Swiftのmutatingキーワードについて - Qiita