SwiftUINavigation框架修改Destination值无法打开目标页面求助
使用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) } } }
问题原因与修复方案
问题核心
- 多余的
onNavigate回调:unwrapping: $destination.case(/Destination.first)已经会在NavigationLink激活时自动将destination设置为对应枚举值,手动在onNavigate中重复设置会触发状态冲突,导致值被异常清空。 - 直接切换枚举值的栈冲突: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
相关产品推荐
相关产品推荐

