3
1

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-08-28

この記事は何

プログラミング初心者が、SwiftUIフレームワークを使ったアプリ開発で最初につまづきやすいのが@State@Bindingの理解。

@State@Bindingを理解するために、実践的なコードを例に挙げて解説する。

全体

Swiftを基礎から学ぶには
自著、工学社より発売中の「まるごと分かるSwiftプログラミング」をお勧めします。変数、関数、フロー制御構文、データ構造はもちろん、構造体からクロージャ、エクステンション、プロトコル、クロージャまでを基礎からわかりやすく解説しています。

Stateプロパティラッパー

以下に定義するMusicPlayerビューは、テキストとボタンからなる単純な画面。
ボタンをタップするたびに、画面(UI)は「一時停止」と「再生」の状態を交互に変化する。

import SwiftUI

struct MusicPlayer: View {
    @State var isPlaying = false
    
    var body: some View {
        VStack {
            Text("Awesome music")
                .font(.title)
                .foregroundStyle(isPlaying ? .primary : .secondary)
            Button {
                isPlaying.toggle()
            } label: {
                Image(systemName: isPlaying ? "pause.circle" : "play.circle")
                    .font(.largeTitle)
                    .foregroundColor(.blue)
            } 
            .padding()
        }        
    }
}

上のコードでは、isPlaying変数に@Stateがマークされている。
@Stateがマークされた変数は「ビューのステート(状態)」であり、SwiftUIによって「その値の状態」が追跡される。
@State変数の値が変更されると、SwiftUIはそのビューを更新して、画面の最新状態を表示する。

‎State and Binding Basics.‎001.png

このisPlaying変数については、bodyプロパティの外側で宣言されている点にも注目。
これは、「ビューとステート(状態)の分離」を意味している。

Bindingプロパティラッパー

上記の例におけるMusicPlayer型は、定義するUI自体は単純な割にコードが複雑に見える。
そのような場合、一部のビューを抽象化することで、保守性や可読性を改善できる。

以下のコードは、ボタン部分だけを抽象化したPlayButtonビューを定義する。

PlayButtonビュー
struct PlayButton: View {
    @Binding var isPlay: Bool
    
    var body: some View {
        Button {
            isPlay.toggle()
        } label: {
            Image(systemName: isPlay ? "pause.circle" : "play.circle")
                .font(.largeTitle)
                .foregroundColor(.blue)
        } 
        .padding()
    }
}

上のコードでは、isPlay変数にマークされた@Bindingに注目。
このisPlay変数はBool型だが、既定値がない。
したがって、PlayButtonビューの初期化の際には既定値を設定することになる。
@Bindingな変数を初期化するために設定できる既定値は通常の値ではなく、「SwiftUIが追跡する@State変数への参照」を設定する。
例えば、PlayButton()イニシャライザのisPlayパラメータに設定するのは通常のBool値ではなく、Binding<Bool>型のバインド値を渡す。

ビューにバインドを渡す

@Bindingな変数を初期化するために「SwiftUIが追跡する@State変数への参照」を設定するには、@Stateな変数の先頭に$記号を記述する。

以下のコードでは、PlayButtonビューの@Binding変数を初期化する際に「SwiftUIが追跡する@State変数への参照」を設定している。

ボタンを抽象化したコード
struct MusicPlayer: View {
    @State var isPlaying = false
    
    var body: some View {
        VStack {
            Text("Awesome music")
                .font(.title)
                .foregroundStyle(isPlaying ? .primary : .secondary)
            PlayButton(isPlay: $isPlaying)
        }        
    }
}

上のコードにおいて、$isPlayingは「SwiftUIがPlayButtonビューを経由して、isPlaying変数を追跡する」ことを意味する。
つまり、PlayButtonビューに「isPlaying変数のバインドを渡した(あるいは、isPlaying変数はバインドされた)」ことになる。

‎State and Binding Basics.‎002.png

MusicPlayerビューのコードは保守性と可読性が改善されて、実際のUI画面と同じくらい単純に出来た。

3
1
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
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?