Hello,
The app displays a list of posts (Post), and for each post, a list of tags (Tag). The Post detail view shows a list of tags for a given post. The Tag detail view shows the post name and the tag name. Both Post and Tag are ObservableObject, and both are passed to the environment when a NavigationLink is tapped.
On the master List with all the posts, you tap on a post. The post is passed in the environment. It's working because the detail view for the selected post is correctly displayed, and you can choose to display a tag from the tags in the displayed post.
But when you tap on a tag to view the details, the app crashes: the post object is not in the environment. No ObservableObject of type Post found. A View.environmentObject(_:) for Post may be missing as an ancestor of this view.
Why? The post object in the PostView, so it should be also available in the TagView because the TagView can only be displayed from the PostView.
Thanks Axel
import SwiftUI
class Store: ObservableObject {
@Published var posts: [Post] = [
Post(name: "Post 1", tags: [.init(name: "Tag 1"), .init(name: "Tag 2")]),
Post(name: "Post 2", tags: [.init(name: "Tag 1"), .init(name: "Tag 2")])
]
}
class Post: ObservableObject, Identifiable, Hashable {
@Published var name: String = ""
@Published var tags: [Tag] = []
var id: String { name }
init(name: String, tags: [Tag]) {
self.name = name
self.tags = tags
}
static func == (lhs: Post, rhs: Post) -> Bool {
return lhs.id == rhs.id
}
func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
}
class Tag: ObservableObject, Identifiable, Hashable {
@Published var name: String = ""
var id: String { name }
init(name: String) {
self.name = name
}
static func == (lhs: Tag, rhs: Tag) -> Bool {
return lhs.id == rhs.id
}
func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
}
struct PassEnvironmentObject: View {
@StateObject private var store: Store = .init()
var body: some View {
NavigationStack {
List {
ForEach(store.posts) { post in
NavigationLink(post.name, value: post)
}
}
.navigationDestination(for: Post.self) { post in
PostView()
.environmentObject(post)
}
.navigationDestination(for: Tag.self) { tag in
TagView()
.environmentObject(tag)
}
}
}
}
struct PostView: View {
@EnvironmentObject private var post: Post
var body: some View {
List {
ForEach(post.tags) { tag in
NavigationLink(tag.name, value: tag)
}
}
}
}
struct TagView: View {
@EnvironmentObject private var post: Post
@EnvironmentObject private var tag: Tag
var body: some View {
VStack {
Text(post.name)
Text(tag.name)
}
}
}
struct PassEnvironmentObject_Previews: PreviewProvider {
static var previews: some View {
PassEnvironmentObject()
}
}