【Swift】インスタンス変数の変化を検知【SwiftUI】

Swift

定義したインスタンス変数の値が変更されたときに、それをトリガーに何か処理したいことはよくあると思います。今回はその方法を説明します。

環境

  • 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()
    }
}

コメント

タイトルとURLをコピーしました