SwiftUI の NavigationView で複数回遷移する時がある
初めての iOS アプリを SwiftUI で書いてみたら、 NavigationLink の遷移が複数回発生したのでメモ
対処はしてないので、読み進めても何も解決策は書いてません
環境は
- Xcode 12.4
- Simulator (iOS 14.4)
挙動の再現するコードはこんな感じ
よくある NavigationBar のボタンで画面遷移するやつ
Timer を使用しているところは、実際に作ったものだとネットワーク経由のデータ取得をしてる
import SwiftUI
class ViewModel: ObservableObject {
@Published var message = "aaa"
init(_ number: Int) {
Timer.scheduledTimer(withTimeInterval: 3.0, repeats: false) { _ in
self.message = "bbb"
print("timer end \(number)")
}
}
}
struct MainView: View {
@ObservedObject var vm: ViewModel
var body: some View {
NavigationView {
Text(message)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
NavigationLink(destination: SubView()) {
Text("Show")
}
}
}
}
}
}
struct SubView: View {
@ObservedObject var vm: ViewModel
var body: some View {
Text("Sub view")
}
}
これで Timer.scheduledTimer の block が実行される前に SubView に遷移すると、 block が実行されるタイミングで再度遷移する
ページのスタックが MainView -> SubView -> SubView になってしまうので、 NavigationBar の戻るをタップしても SubView が出る
なぜこの動きになるのかは調べたいけど、 Jetpack Compose の State Hoisting みたいに 状態管理を基点の View かその上にまで持ち上げる設計に直す方が優先な気がする
ちなみに SubView から ObservedObject を消すと発生しない
あとはこんな感じで toolbar から外すと遷移は 1 回だけになる
struct MainView: View {
@ObservedObject var vm: ViewModel
var body: some View {
NavigationView {
- Text(message)
- .toolbar {
- ToolbarItem(placement: .navigationBarTrailing) {
- NavigationLink(destination: SubView()) {
- Text("Show")
- }
- }
- }
+ VStack {
+ Text(message)
+ NavigationLink(destination: SubView()) {
+ Text("Show")
+ }
+ }
}
}
}