🐞
SwiftUI 3に出たデバッグ時の便利機能
この記事はAppify Advent Calendar 2021 の12/13 の記事です。
こんにちは Appify Technologies で業務委託で携わっている bannzai です。この記事ではSwiftUI 3から使えるちょっとおもしろ機能を紹介します
_printChanges
Viewのstatic funcに _printChanges
と言うプライベートメソッドが生えています。これは body
の中で使うことが想定されています。これを使うとViewが変更されるタイミングで何起因で変更されたかをチェックすることができます。
例えば下のようなViewとViewModelがあったとします。
@MainActor public class ViewModel: ObservableObject {
@Published var value = ""
func call() async {
await Task.sleep(1_000_000_000)
value = "called"
}
}
public struct ContentView: View {
@State var count1 = 0
@State var count2 = 0
@StateObject var viewModel = ViewModel()
public var body: some View {
let _ = Self._printChanges()
VStack(spacing: 16) {
VStack {
Button(action: {
count1 += 1
}, label: {
Text("Button 1")
})
Text("Count1 is \(count1)")
}
Button(action: {
count2 += 1
}, label: {
Text("Button 2")
})
}
.task {
await viewModel.call()
}
}
}
前述した通り_printChanges
を使う場合はViewのbodyの中で使います。さらにstatic funcなので Self._printChanges()
の形式で呼びます。ただしbodyの中でvoidが返り値のfunctionは呼べないので let _ =
を用いてコンパイルエラーを回避しています
ここでは @State
プロパティが2つ、@StateObject
を一つ用意して値を変化させようと思います。
アプリの画面のスクショ
実際に使っているところのgif
ちょっと画質が荒いのでコンソールに出ている結果を載せます。出力内容が ContentView:
でフィルタリングした結果になります。
ContentView: @self, @identity, _count1, _count2, _viewModel changed.
ContentView: _viewModel changed.
ContentView: _count1 changed.
ContentView: _count1 changed.
ContentView: _count1 changed.
コンソールの内容
- まず最初の行の
@self,@identity
から始まるものはContentView
のインスタンスができた時に表示されるものです - 次に
_viewModel changed
は.task
の中で1秒待った後にViewModel
の@Published
なプロパティを更新しています。その変更を検知してコンソールにログが出ています。ちなみに@Published
なプロパティをView
で使用しているかどうかにかかわらずprintされます -
_count1 changed
の部分についてです。Button1を2回押したことにより、@State var count1
の値が2回インクリメントされました。その結果がコンソールに出ています。 - コンソールには出ていませんが、gifではこの後にButton2を1回押しました。しかし、コンソールには何も出力されませんでした。Button1との差分は変更しているプロパティが
@State var count2
であること、そして、count2
はインクリメント以外では使用されていません。count1
の方ではText
の表示内容として使っていました。つまり、@State
の更新内容によってView
が変わらないようであれば更新が走らないみたいですね。賢い - 最後の
_count1
は_count2
のButton押下時に不具合があったとかじゃないよ。との確認用です。先ほどと同様にcount1
が変わったら_count1 changed
と表示されることが確認できました
まとめ
SwiftUIの内部的な動きが除けて面白いですね。デバッグ時にも役に立つ場面があると思います。プライベートAPIなのでこのコードを入れてアプリを審査に出すと多分リジェクトされるのでその点は気をつけましょう
おしまい\(^o^)/
Discussion
雑にメモ。
_logChanges
が Xcode 15.1 から登場した。_printChangesとの違いはXcodeのコンソールに infoレベルのログとして Subsystem:com.apple.SwiftUI
, Category:Changed Body Properties
で区分されて表示される