この記事は何
プログラミング初心者が、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はそのビューを更新して、画面の最新状態を表示する。
このisPlaying変数については、bodyプロパティの外側で宣言されている点にも注目。
これは、「ビューとステート(状態)の分離」を意味している。
Bindingプロパティラッパー
上記の例におけるMusicPlayer型は、定義するUI自体は単純な割にコードが複雑に見える。
そのような場合、一部のビューを抽象化することで、保守性や可読性を改善できる。
以下のコードは、ボタン部分だけを抽象化した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変数はバインドされた)」ことになる。
MusicPlayerビューのコードは保守性と可読性が改善されて、実際のUI画面と同じくらい単純に出来た。


