この記事は何
プログラミング初心者が、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画面と同じくらい単純に出来た。