定義したインスタンス変数の値が変更されたときに、それをトリガーに何か処理したいことはよくあると思います。今回はその方法を説明します。
環境
- Xcode13.3
- 動作の確認はiOS15 iPhone12 Pro MAXで行っています
SwiftUIを使っていて、再描画を行いたいなら@State
SwiftUIを使って開発しているのであれば@Stateを使用することで簡単に値の変化を検知して再描画することができます。(正確には「してくれます。」の方が正しいか。)
@Stateをつけたプロパティはメモリの管理がSwiftUIフレームワークに委譲されるため、値の変更が可能になります。また、このプロパティの値とUIの状態は同期されます。書き方は以下のような感じ。
struct ContentView: View {
@State var text: String = "Hello"
var body: some View {
VStack {
Text(text)
}
.padding()
}
}
SwiftならdidSet、willSet
再描画ではなく独自の処理を行いたい場合や、SwiftUIを使っていない場合などはdidSet
/willSet
を使えます。
使い方はこんな感じ。willSet
の中ではnewValue
で新しく代入される値を参照できます。didSetの中ではoldValue
で代入される前の古い値を参照できます。
struct User {
var id: String
var nickname: String {
// 値を変更する前に実行される
willSet {
print(":\(nickname)\n変更後:\(newValue)")
}
// 値の変更処理後に実行される
didSet {
if (nickname == oldValue) {
print("同じニックネームは設定できません。")
nickname = oldValue
}
}
}
}
var user = User(id: "abcdefg", nickname: "タロウ")
user.nickname = "ジロウ" // <-ここでwillSetとdidSetが実行される
@Stateと併用するときはonChange
SwiftUI内で@StateとdidSet
を併用しようとすると、didSet
が期待通りに動いてくれません。そういった場合はonChange
を使用しましょう。
struct ContentView: View {
@State var text:String = "Hello"
var body: some View {
VStack {
Text(text)
}
.onChange(of: text) { newValue in
print("テキストが変更されました \(newValue)")
}
.padding()
}
}
コメント