🕌
【SwiftUI】EnvironmentObjectをNavigationLinkで遷移するViewに渡す挙動実験
概要
- SwiftUIのEnvironmentObjectでは、親Viewで設定されていても、NavigationLinkで遷移する先にViewで利用できないという点に躓いた。
- その挙動を確認する
環境
- Xcode 15.4.0
実験コード
SampleApp.swift
class AppData: ObservableObject {
@Published var count = 0
}
@main
struct EnvironmentObjectLearingApp: App {
@StateObject private var appData = AppData()
var body: some Scene {
WindowGroup {
TopView()
.environmentObject(appData)
}
}
}
TopView.swift
class TopData: ObservableObject {
@Published var count: Int = 0
}
struct TopView: View {
@EnvironmentObject var appData: AppData
@StateObject private var topData = TopData()
var body: some View {
NavigationStack {
VStack {
Text("TopView")
Text("appData.count \(appData.count)")
Button("increment") { appData.count += 1 }
Text("topData.count \(topData.count)")
Button("increment") { topData.count += 1 }
Spacer().frame(height: 20)
SecondView()
}
.environmentObject(topData)
}
}
}
SecondView, ThirdView, NestedView.swift
struct SecondView: View {
@EnvironmentObject var appData: AppData
@EnvironmentObject var topData: TopData
var body: some View {
VStack {
Text("SecondView")
Text("appData.count \(appData.count)")
Button("increment") { appData.count += 1 }
Text("topData.count \(topData.count)")
Button("increment") { topData.count += 1 }
Spacer().frame(height: 20)
ThirdView()
Spacer().frame(height: 20)
NavigationLink {
NestedView()
.environmentObject(topData)
// 上記の.environmentObject(topData)の行が存在しない場合、NestedViewでtopDataを利用する際に以下のエラーが発生する
// Fatal error: No ObservableObject of type TopData found. A View.environmentObject(_:) for TopData may be missing as an ancestor of this view.
} label: {
Text("To NestedView")
}
}
.background(Color.yellow)
}
}
struct ThirdView: View {
@EnvironmentObject var appData: AppData
@EnvironmentObject var topData: TopData
var body: some View {
VStack {
Text("ThirdView")
Text("appData.count \(appData.count)")
Button("increment") { appData.count += 1 }
Text("topData.count \(topData.count)")
Button("increment") { topData.count += 1 }
}
.background(Color.orange)
}
}
struct NestedView: View {
@EnvironmentObject var appData: AppData
@EnvironmentObject var topData: TopData
var body: some View {
VStack {
Text("NestedView")
Text("appData.count \(appData.count)")
Button("increment") { appData.count += 1 }
Text("topData.count \(topData.count)")
Button("increment") { topData.count += 1 }
}
.background(Color.cyan)
}
}
結果
- 以下の通り、NavigationStackの中で渡されたenvironmentObject(TopData)は、NavigationLinkの先のviewに対してはあたらめて渡す必要がある
NavigationLink {
NestedView()
.environmentObject(topData)
} label: {
Text("To NestedView")
}
Discussion