SwiftUI Landmarks 应用程序教程屏幕在切换收藏夹时返回

Kai*_*Kai 1 ios swift swiftui

我正在关注这个SwiftUI 教程并下载了项目文件

我在没有任何修改的情况下构建并运行了完整的项目。在应用程序中,如果我:

  1. 在列表视图中打开“仅显示收藏夹”
  2. 点击“海龟岩”或“奇尔库特小径”详细信息视图
  3. 在详细视图中,我切换了收藏夹按钮(黄色星形图标)

屏幕将自行跳回列表视图。

但是,如果我点击列表视图中最后一个项目(“圣玛丽湖”)的详细信息视图,我可以打开和关闭黄色星形按钮,并且仍然保持在相同的详细信息视图中。

谁能解释这种行为?我需要做什么才能留在详细信息视图中而不被迫导航回列表视图?

Asp*_*eri 5

好吧,实际上它是 SwiftUI 缺陷,视图层次结构外的视图不能刷新(即body调用)-它应该在下次出现后立即更新。(我提交了反馈 #FB7659875,并建议对每个受影响的人都做同样的事情 - 当重复更好时就是这种情况)

同时,以下是可能的临时解决方法(但即使在 Apple 修复问题后它仍会继续工作,因此是安全的)。这个想法是使用本地视图状态模型作为视图和已发布属性之间的中间体,并使其仅在视图可见时更新。

仅提供了要在提到的项目中替换的更正视图。

使用 Xcode 11.4 / iOS 13.4 测试 - 没有意外的“跳回”

演示

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"))
        }
    }
}
Run Code Online (Sandbox Code Playgroud)