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

SwiftUI NavigationLink跳转时重复实例化目标视图问题

问题成因

你的判断完全正确,重复跳转3次的bug和列表共3行直接相关,核心问题是列表内所有行的NavigationLink共用了同一个激活状态绑定。

SwiftUI渲染List时,会为每一个可见行创建对应的视图实例,你写的3行列表就对应3个独立的NavigationLink实例,这3个实例全部绑定了同一个isActive计算属性、同一个destination状态。当你点击某一行修改destination值后,isActive会同步变为true,3个NavigationLink同时监听到激活状态变更,就会依次触发跳转,最终连续弹出3层目标视图。

除此之外你的代码还有两个会引发后续异常的隐患:

  • 在MenuViewOptionRowView内部直接初始化UserSettingsStore(),会导致每渲染一行就新建一个store实例,全局选中状态根本无法同步,对勾显示逻辑会失效。
  • 给NavigationLink的展示内容额外添加onTapGesture,会和NavigationLink原生的点击事件冲突,后续大概率出现点击无响应、跳转状态错乱的问题。
修复方案

SwiftUI针对列表中多跳转项的场景,原生提供了tag+selection的NavigationLink绑定方式,不需要自己手写共用的isActive绑定,修复步骤如下:

  1. 调整父视图MenuViewOptions的状态持有逻辑,改用selection绑定模式管理跳转,把全局状态UserSettingsStore提到父视图统一持有:
struct MenuViewOptions: View {
    @State private var selectedDestination: MenuViewType?
    @StateObject private var userSettingsStore = UserSettingsStore()
    
    var body: some View {
        VStack {
            List(SettingsOptions().menuViewSettingsOptions) { item in
                NavigationLink(
                    tag: MenuViewType(rawValue: item.id)!,
                    selection: $selectedDestination,
                    destination: { selectedDestination?.view }
                ) {
                    MenuViewOptionRowView(
                        menuViewItem: item,
                        userSettingsStore: userSettingsStore,
                        selectedDestination: $selectedDestination
                    )
                }
            }
        }.navigationBarTitle("Settings")
    }
}
  1. 调整行视图MenuViewOptionRowView,移除内部新建的store实例和多余的点击手势,通过传参接收父视图的状态,跳转前的设置项更新逻辑改用状态监听实现:
struct MenuViewOptionRowView: View {
    let menuViewItem: MenuViewSettingsItem
    @ObservedObject var userSettingsStore: UserSettingsStore
    @Binding var selectedDestination: MenuViewType?

    var body: some View {
        HStack {
            Image(systemName: menuViewItem.imageName)
                .circularImageStyle(width: 15, height: 15, padding: 5, backgroundColor: Color(red: 34 / 255, green: 34 / 255, blue: 34 / 255), foregroundColor: Color(red: 23 / 255, green: 121 / 255, blue: 232 / 255))
            Text(menuViewItem.name)
            Spacer()
            if menuViewItem.id == userSettingsStore.menuViewSelection {
                Image(systemName: "checkmark").foregroundColor(Color(red: 23 / 255, green: 121 / 255, blue: 232 / 255))
            }
        }
        .onChange(of: selectedDestination) { newValue in
            guard let selected = newValue else { return }
            userSettingsStore.menuViewSelection = selected.rawValue
        }
    }
}

这种写法下,SwiftUI会自动匹配和当前selection值tag一致的NavigationLink触发跳转,不会出现所有链接同时响应的问题;状态统一收归父视图持有,也从根源上避免了子视图重复初始化状态对象导致的各类异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 04:48:19