You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUINavigation框架修改Destination值无法打开目标页面求助

SwiftUINavigation枚举导航问题:切换页面时旧页面关闭但新页面无法打开

使用SwiftUINavigation框架实现基于枚举的导航,设置深度链接时遇到异常:修改destination枚举值时,当前页面会关闭,但目标页面无法打开。推测是NavigationLink的绑定逻辑在切换枚举值时,会先将原有值清空,导致新页面无法正常激活。期望的行为是:在第一个页面点击“打开第二个页面”按钮时,关闭第一个页面并打开第二个页面。

使用环境:Xcode 14.2,iPhone 8模拟器(iOS 15.5)

原问题代码

import SwiftUI
import SwiftUINavigation

struct ContentView: View {
    enum Destination {
        case first
        case second
    }

    @State var destination: Destination?

    var body: some View {
        NavigationView {
            VStack {
                NavigationLink(
                    unwrapping: $destination.case(/Destination.first),
                    onNavigate: { isActive in
                        if isActive {
                            destination = .first
                        }
                    },
                    destination: { token in
                        NextView(buttonTitle: "Open Second View") {
                            destination = .second
                        } close: {
                            destination = nil
                        }
                    },
                    label: {
                        Text("Open First View")
                    }
                )

                NavigationLink(
                    unwrapping: $destination.case(/Destination.second),
                    onNavigate: { isActive in
                        if isActive {
                            destination = .second
                        }
                    },
                    destination: { token in
                        NextView(buttonTitle: "Open First View") {
                            destination = .first
                        } close: {
                            destination = nil
                        }
                    },
                    label: {
                        Text("Open Second View")
                    }
                )
            }
        }
    }
}

struct NextView: View {
    let buttonTitle: String
    let closure: () -> Void
    let close: () -> Void

    var body: some View {
        VStack {
            Button(buttonTitle, action: closure)
            Button("Close", action: close)
        }
    }
}

问题原因与修复方案

问题核心

  1. 多余的onNavigate回调:unwrapping: $destination.case(/Destination.first)已经会在NavigationLink激活时自动将destination设置为对应枚举值,手动在onNavigate中重复设置会触发状态冲突,导致值被异常清空。
  2. 直接切换枚举值的栈冲突:iOS15的NavigationView栈结构下,直接将destination从.first改为.second时,原有NavigationLink绑定失效会优先清空状态,新的NavigationLink无法及时激活。

修复代码

步骤1:移除多余的onNavigate回调

删除两个NavigationLink中的onNavigate参数,让unwrapping绑定自动处理状态更新:

NavigationLink(
    unwrapping: $destination.case(/Destination.first),
    destination: { token in
        NextView(buttonTitle: "Open Second View") {
            // 调整切换逻辑:先关闭当前页面,再打开新页面
            destination = nil
            DispatchQueue.main.async {
                destination = .second
            }
        } close: {
            destination = nil
        }
    },
    label: {
        Text("Open First View")
    }
)

NavigationLink(
    unwrapping: $destination.case(/Destination.second),
    destination: { token in
        NextView(buttonTitle: "Open First View") {
            // 调整切换逻辑:先关闭当前页面,再打开新页面
            destination = nil
            DispatchQueue.main.async {
                destination = .first
            }
        } close: {
            destination = nil
        }
    },
    label: {
        Text("Open Second View")
    }
)

步骤2:调整页面切换逻辑

在NextView的切换按钮回调中,先将destination设为nil关闭当前页面,再通过DispatchQueue.main.async延迟设置新的枚举值,确保NavigationView有足够时间更新栈状态,避免状态冲突。

替代优化方案(iOS16+兼容)

如果可以升级到iOS16及以上,推荐使用NavigationStack配合navigationDestination,状态管理更简洁可靠:

struct ContentView: View {
    enum Destination {
        case first
        case second
    }

    @State var destination: Destination?

    var body: some View {
        NavigationStack {
            VStack {
                Button("Open First View") {
                    destination = .first
                }
                Button("Open Second View") {
                    destination = .second
                }
            }
            .navigationDestination(unwrapping: $destination) { $dest in
                switch dest {
                case .first:
                    NextView(buttonTitle: "Open Second View") {
                        destination = .second
                    } close: {
                        destination = nil
                    }
                case .second:
                    NextView(buttonTitle: "Open First View") {
                        destination = .first
                    } close: {
                        destination = nil
                    }
                }
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者Nikita Tepliakov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 00:38:10