Well, actually it is SwiftUI defect, the View being out of view hierarchy must not be refreshed (ie. body
called) - it should be updated right after next appearance. (I submitted feedback #FB7659875, and recommend to do the same for everyone affected - this is the case when duplicates are better)
Meanwhile, below is possible temporary workaround (however it will continue work even after Apple fix the issue, so it is safe). The idea is to use local view state model as intermediate between view and published property and make it updated only when view is visible.
Provided only corrected view to be replaced in mentioned project.
Tested with Xcode 11.4 / iOS 13.4 - no unexpected "jump back"
struct LandmarkList: View {
@EnvironmentObject private var userData: UserData
@State private var landmarks = [Landmark]() // local model
@State private var isVisible = false // own visibility state
var body: some View {
NavigationView {
List {
Toggle(isOn: $userData.showFavoritesOnly) {
Text("Show Favorites Only")
}
ForEach(landmarks) { landmark in
if !self.userData.showFavoritesOnly || landmark.isFavorite {
NavigationLink(
destination: LandmarkDetail(landmark: landmark)
.environmentObject(self.userData)
) {
LandmarkRow(landmark: landmark)
}
}
}
}
.onReceive(userData.$landmarks) { array in // observe external model
if self.isVisible {
self.landmarks = array // update local only if visible
}
}
.onAppear {
self.isVisible = true // track own state
self.landmarks = self.userData.landmarks
}
.onDisappear { self.isVisible = false } // track own state
.navigationBarTitle(Text("Landmarks"))
}
}
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…