[SwiftUI] onChange まとめ@2023

SwiftUI2021

     
⌛️ 2 min.
onChange の使い方についてまとめます。(2023.Nov時点)

環境&対象

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

  • macOS14.2 Beta 3
  • Xcode 15.1 beta 3
  • iOS 17.2
  • Swift 5.9

onChange

onChange は、Value 型変数の更新に伴って、何らかの動作を行いたいときに使うことのできる View Modifier です。

2023.Nov 時点では、以下の 2種類用意されています。

・変更されたときに実行する動作を指定する ViewModifier
・変更された時の変更前後の値を参照しながら、動作を指定できる ViewModifier

MEMO

onChange は、Equatable の性質を利用して 変更されたかどうかの判定を行います。
つまり、監視対象の変数は、Equatable に準拠していないといけません。

値なし

(シンプルな方の) onChange の signature は、以下の通りです。

public func onChange(of value: V, initial: Bool = false, _ action: @escaping () -> Void) -> some View where V : Equatable

value として指定した変数が変更されたときに、action として指定された closure が実行されます。

使用例

以下は使用例です。

ボタンが押下され、変数の値が+1されたときに、print 文が実行されます。

//
//  ContentView.swift
//
//  Created by : Tomoaki Yagishita on 2023/11/23
//  © 2023  SmallDeskSoftware
//

import SwiftUI

struct ContentView: View {
    @State private var count = 0
    var body: some View {
        VStack {
            Text("Count: \(count)")
            Button(action: {
                count += 1
            }, label: { Text("+1") })
        }
        .onChange(of: count) {
            print("count is changed !")
        }
        .padding()
    }
}

#Preview {
    ContentView()
}

Button を押下すると、コンソールに “count is changed !” と表示されます。

これは、count が変更されると onChange が呼び出されるためです。

値付き

変数を監視しているときに、変更された事実だけではなく 変更された値(と 以前の値)がほしいケースがあります。

そのように、変更前後の値を closure に渡してくれる onChange も用意されています。

signature は以下のようになっています。

public func onChange(of value: V, initial: Bool = false, _ action: @escaping (_ oldValue: V, _ newValue: V) -> Void) -> some View where V : Equatable

この onChange を使用すると、以下のように 変更前後の値を使用した処理を実行させることが可能です。

//
//  ContentView.swift
//
//  Created by : Tomoaki Yagishita on 2023/11/23
//  © 2023  SmallDeskSoftware
//

import SwiftUI

struct ContentView: View {
    @State private var count = 0
    var body: some View {
        VStack {
            Text("Count: \(count)")
            Button(action: {
                count += 1
            }, label: { Text("+1") })
        }
        .onChange(of: count) { (oldValue, newValue) in
            print("count is changed ! \(oldValue) -> \(newValue)")
        }
        .padding()
    }
}

#Preview {
    ContentView()
}

上記の例では、oldValue, newValue として 変更前後の値を参照しています。

onChange の initial 引数

onChange の 2 つの signature をよく見ると、initial という引数があります。

この initial という引数を使用すると、View が表示されるタイミングで onChange を実行させることができます。いわゆる onAppear 相当の処理になります。

なお、変更前後の値が渡される onChange には、変更前 と 変更後の値として同じ値が渡されてきます。

MEMO

試した範囲では onAppear と onChange(initial: true) の呼び出し順序は、記述の順序になっていましたが、ドキュメントには特に記載はありません。

onChange (iOS16/macOS13以前)

onChange という ViewModifier は、iOS17/macOS14 以前にも存在していましたが、すこし signature が異なりました。

public func onChange(of value: V, perform action: @escaping (_ newValue: V) -> Void) -> some View where V : Equatable

上記のように、新規の値のみが 渡されてきていました。

この onChange でも Swift の機能である キャプチャ を使用することで 変更前の値を参照することはできました。

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

まとめ

onChange は、iOS17/macOS14 で signature が更新されて 2種類の onChange になった。

onChange は、iOS17/macOS14 で signature が更新されて 2種類になった
  • 変数の値情報なしに、closure を実行する onChange
  • 変更前後の値情報を与えられる closure を実行する onChange
  • initial を指定することで、onAppear 時に実行させることも可能になった
  • 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版が最新版です。

コメントを残す

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