当将新值推送到 NavigationStack 时,SwiftUI 的 navigationDestination 已在堆栈的早期声明

Sam*_*ies 4 ios swift swiftui swiftui-navigationlink swiftui-navigationstack

我正在尝试在 SwiftUI 中重新创建许多社交媒体应用程序中看到的帐户关注者流程。

\n
    \n
  1. 您按下个人资料上的按钮即可查看您的关注者列表
  2. \n
  3. 您可以点击您的任何一位关注者来查看他们的帐户
  4. \n
  5. 您可以按他们个人资料上的按钮来查看他们的关注者列表
  6. \n
  7. 您可以点击他们的任何一位关注者来查看他们的帐户
  8. \n
\n

步骤 3 和 4 可以永远继续下去(下面是另一个例子):

\n
MyProfile -> Followers (my followers list) -> FollowerView -> Followers (their followers list) -> FollowerView -> Followers (their followers list) -> FollowerView and so on...\n
Run Code Online (Sandbox Code Playgroud)\n

然而,通过运行下面的实现,XCode 控制台会打印:

\n
\n

\xe2\x80\x9cmyApp.SomeProfile\xe2\x80\x9d 的 navigationDestination 已在堆栈的较早位置声明。仅使用最接近堆栈根视图声明的目标。

\n
\n

我知道为什么会这样,但不确定如何解决这个问题。我也认为用作值的类型是否NavigationLink合适,因为它是Int。将其替换为更自定义的类型会更好吗?

\n

任何帮助将不胜感激。

\n
// Enum with custom options\nenum ViewOptions: Hashable {\n    case followers(Int)\n    \n    @ViewBuilder func view(_ path: Binding<NavigationPath>, id: Int) -> some View {\n        FollowersList(path: path, id: id)\n    }\n}\n// Root view\nstruct MyProfileView: View {\n    @State private var path: NavigationPath = .init()\n    \n    var body: some View {\n        NavigationStack(path: $path) {\n            VStack {\n                Text(myProfile.username)\n                Button("See followers") {\n                    path.append(ViewOptions.followers(myProfile.id))\n                }\n                .navigationDestination(for: ViewOptions.self) { option in\n                    option.view($path, id: myProfile.id)\n                }\n            }\n        }\n    }\n}\nstruct FollowersList: View {\n    @Binding var path: NavigationPath\n    var id: Int\n    \n    var body: some View {\n        List(getFollowers(for: id), id:\\.id) { follower in\n            NavigationLink(follower.username, value: follower)\n        }\n        .navigationDestination(for: SomeProfile.self) { profile in\n            switch profile.isMe {\n            case true:  Text("This is your profile")\n            case false: SomeProfileView(path: $path, profile: profile)\n            }\n        }\n    }\n}\nstruct SomeProfileView: View {\n    @Binding var path: NavigationPath\n    \n    var profile: SomeProfile\n    var body: some View {\n        VStack {\n            Text(profile.username)\n            Button("See followers") {\n                path.append(ViewOptions.followers(profile.id))\n            }\n        }\n    }\n}\n\n// ----- Types & functions -----\n\n// Example type for my profile\nstruct MyProfile: Identifiable, Hashable {\n    var id: Int\n    var username: String\n}\n// Example type for profiles reached via navigation link\n// (can be my profile but with reduced functionality e.g. no follow button)\nstruct SomeProfile: Identifiable, Hashable {\n    var id: Int\n    var username: String\n    let isMe: Bool\n}\n// example myProfile (IRL would be stored in a database)\nlet myProfile = MyProfile(id: 0, username: "my profile")\n// example users (IRL would be stored in a database)\nlet meVisited = SomeProfile(id: 0, username: "my profile reached from followers list", isMe: true)\nlet bob       = SomeProfile(id: 1, username: "Bob", isMe: false)\nlet alex      = SomeProfile(id: 2, username: "Alex", isMe: false)\n// example user followers (IRL would be stored in a database)\nlet dict: [Int : [SomeProfile]] = [\n    0 : [bob, alex],\n    1 : [alex, meVisited],\n    2 : [alex, meVisited],\n]\n// example function to get followers of a user (IRL would be a network request)\nfunc getFollowers(for id: Int) -> [SomeProfile] {\n    return dict[id]!\n}\n
Run Code Online (Sandbox Code Playgroud)\n

Moj*_*ini 7

.navigationDestination(...)通过显示包含相同修饰符的视图来重复添加该修饰符。

将所有navigationDestination日志移至关卡中不重复但不一定)的位置NavigationStack

像这样:

NavigationStack(path: $path) {
    VStack {
        Text(myProfile.username)
        Button("See followers") {
            path.append(ViewOptions.followers(myProfile.id))
        }
        .navigationDestination(for: ViewOptions.self) { option in
            option.view($path, id: myProfile.id)
        }
        .navigationDestination(for: SomeProfile.self) { profile in
            switch profile.isMe {
            case true:  Text("This is your profile")
            case false: SomeProfileView(path: $path, profile: profile)
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

所以.navigationDestination(for: SomeProfile.self)不会一次又一次地被创建。

不要忘记将其从FollowersList