[Swift][SwiftUI] willSet/didSet/onChange の使い方

SwiftUI2021

     
⌛️ 2 min.
willSet/didSet/onChange で、新たに設定される値/新たに設定された値だけでなく、変更前の値を取得する方法を説明します。

環境&対象

以下の環境で動作確認を行なっています。

  • macOS Ventura 13.3 Beta
  • Xcode 14.3 Beta2
  • iOS 16.0

willSet/didSet

willSet/didSet は、Swift 言語の持つ Property Observer の1つです。

Swift のドキュメントは、こちら

struct や class 等の プロパティに値を設定する前後に、指定する処理を行うことができます。

willSet は 設定する直前、didSet は、設定した直後に処理されます。

アプリ向け実装としては、特定のプロパティの変更に応じて付随する処理の実行を行います。
デバッグ時には どのオブジェクトがどのタイミングで プロパティを変更してるかを確認するため等に 使えます。

以下は、Swift の Language Reference に言及されているサンプルです。

class StepCounter {
    var totalSteps: Int = 0 {
        willSet(newTotalSteps) {
            print("About to set totalSteps to \(newTotalSteps)")
        }
        didSet {
            if totalSteps > oldValue  {
                print("Added \(totalSteps - oldValue) steps")
            }
        }
    }
}
let stepCounter = StepCounter()
stepCounter.totalSteps = 200
// About to set totalSteps to 200
// Added 200 steps
stepCounter.totalSteps = 360
// About to set totalSteps to 360
// Added 160 steps
stepCounter.totalSteps = 896
// About to set totalSteps to 896
// Added 536 steps

上記の例では willSet では カスタムパラメータとして宣言されている newTotalSteps として これから設定される値を参照しています。カスタムパラメータとして宣言していないときは、newValue として参照できます。
didSet では、設定前の値は カスタムパラメータとして宣言していないので、デフォルトの “oldValue” という変数として参照することができます。willSet と同様にカスタムパラメータとして宣言すると指定した名称で参照できます。

なお、willSet では newValue の値を変更することはできません。(let で定義されています)
意味はありませんが、didSet で oldValue を変更することもできません。
なお、didSet では、自処理のなかで プロパティを再度 変更することは可能です。
例えば 設定された値を元に調整した別の値にすることが可能です。

onChange

SwiftUI では didSet と似た感じの機能を持つ View Modifier として、onChange という ViewModifier が用意されています。
Apple のドキュメントは、こちら

特定の プロパティ等が変更された時に、付随して処理を行いたい時に使用することができます。
ただし、対象は、Equatable に conform している必要があります。

使用例は、以下です。

struct ContentView: View {
  @State private var selectedValue: Int = 0
  var body: some View {
    SomeView()  
      .onChange(of: selectedValue) { newValue in
        // selectedValue と言うプロパティが、設定されたあと、実行される(設定値は、newValue)
        // process something
      }
   }
}

selectedValue という変数が変更された時に、以降の closure が実行されます。

この時に、新しく設定された値は、newValue として受け取ることができます。(該当変数にすでに設定されている値と同じです)

onChange も oldValue を受け取れる

キャプチャを使うことで、didSet と同様に、onChange も変更前の値も受け取ることができるようになっています。
受け取るためには、以下のように記述します。

struct ContentView: View {
  @State private var selectedValue: Int = 0
  var body: some View {
    SomeView()  
      .onChange(of: selectedValue) { [selectedValue] newValue in
        // selectedValue : old Value
        // newValue      : new value
      }
   }
}

なお、変更前の値を別変数名で受け取ることも可能です。

struct ContentView: View {
  @State private var selectedValue: Int = 0
  var body: some View {
    SomeView()  
      .onChange(of: selectedValue) { [myOldValue = selectedValue] newValue in
        // myOldValue    : old Value
        // newValue      : new value
      }
   }
}
注意

ちなみに、onChange は、MainThread で処理されるため、時間のかかる処理を直接実行すると 反応の悪い UI になってしまいますので注意が必要です。

まとめ

willSet/didSet/onChange の使い方を確認しました。

willSet/didSet/onChange の使い方
  • willSet は、プロパティ変更直前に呼ばれる
  • willSet は、newValue という名称の変数で 設定される値を参照できる
  • willSet でカスタムパラメータ定義すると好きな変数名で参照できる
  • didSet は、プロパティ変更直後に呼ばれる
  • didSet は、oldValue という名称の変数で 設定される値を参照できる
  • didSet でもカスタムパラメータ定義すると好きな変数名で参照できる
  • onChange では、closure に newValue 相当が渡されてくる
  • onChange でも、oldValue を取得することができる
  • onChange は、MainThread で処理されるので注意が必要

説明は以上です。
不明な点やおかしな点ありましたら、こちらまで。

SwiftUI おすすめ本

SwiftUI を理解するには、以下の本がおすすめです。

SwiftUI ViewMatery

SwiftUI で開発していくときに、ViewやLayoutのための適切なmodifierを探すのが大変です。
英語での説明になってしまいますが、以下の”SwiftUI Views Mastery Bundle”という本がビジュアル的に確認して探せるので、便利です。

英語ではありますが、1ページに コードと画面が並んでいるので、非常にわかりやすいです。

View に適用できる modifier もわかりやすく説明されているので、ビューの理解だけではなく、どのような装飾ができるかも簡単にわかります。

超便利です

SwiftUIViewsMastery

販売元のページは、こちらです。

SwiftUI 徹底入門

# SwiftUI は、毎年大きく改善されていますので、少し古くなってしまいましたが、いまでも 定番本です。

Swift学習におすすめの本

詳解Swift

Swift の学習には、詳解 Swift という書籍が、おすすめです。

著者は、Swift の初期から書籍を出していますし、Swift の前に主力言語だった Objective-C という言語についても同様の書籍を出しています。

最新版を購入するのがおすすめです。

現時点では、上記の Swift 5 に対応した第5版が最新版です。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です