I'm working through the Apple SwiftUI tutorials, and I'm encountering an issue where child views automatically return to the parent view whenever they change a variable in an @EnvironmentObject.
The parent LandmarkList view functionality allows navigation to any child view in a list of Landmarks, with the ability to filter for only those child views that are "Favorites" of the user.
struct ContentView: View {
@EnvironmentObject var modelData: ModelData
@State private var showFavoritesOnly = true
var filteredLandmarks: [Landmark] {
modelData.landmarks.filter { landmark in
(!showFavoritesOnly || landmark.isFavorite)
}
}
var body: some View {
NavigationView {
List{
Toggle(isOn: $showFavoritesOnly) {
Text("Favorites only")
}
ForEach(filteredLandmarks) { landmark in
NavigationLink(destination: LandmarkDetail(landmark: landmark)) {
LandmarkRow(landmark: landmark)
}
}
}
.navigationBarTitle("Landmarks")
}
}
}
final class ModelData: ObservableObject {
@Published var landmarks: [Landmark] = load("/landmarkData.json")
}
When within the child view (and only when the "Favorites only" is toggled to ON in the parent LandmarkList view), if the user changes the "Favorite" status via the FavoriteButton, the view immediately returns to the parent view. More confusingly, this happens for every child view in the parent LandmarkList EXCEPT whichever Landmark is in the last row (which allows for changing the "Favorite" status on and off without displaying this behavior).
struct LandmarkDetail: View {
@EnvironmentObject var modelData: ModelData
var landmark: Landmark
var landmarkIndex: Int {
modelData.landmarks.firstIndex(where: { $0.id == landmark.id })!
}
var body: some View {
ScrollView {
VStack(alignment: .leading) {
Text(landmark.name)
.font(.title)
.foregroundColor(.primary)
FavoriteButton(isSet: $modelData.landmarks[landmarkIndex].isFavorite)
}
.navigationBarTitle(landmark.name)
}
}
}