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

SwiftUI导航链接点击一次后报错求助:视图更新内禁止发布变更

问题分析与修复方案

问题根源

  • 多个独立的isLinkActive状态变量,返回页面后未重置为false,导致再次点击时NavigationLink的激活状态冲突,触发SwiftUI导航栈异常。
  • 在onTapGesture中同时修改selected和多个激活状态,属于视图更新过程中发布状态变更,违反SwiftUI状态更新规则,引发未定义行为警告。

修复步骤

1. 简化状态管理

删除所有isLinkActive系列变量,改用单个可选枚举变量管理跳转目标,避免状态分散:

// 定义跳转目标枚举
enum Destination {
    case propertyFilter, student, card, rentalForm, flashLane, easyPass
}

// 在MainMenu结构体中替换原有状态
@State private var destination: Destination?

将所有NavigationLink从循环中移出,放到NavigationView的根层级,使用NavigationLink(item:)绑定状态,返回时自动重置状态:

// 放在ScrollView同级的ZStack中
NavigationLink(item: $destination) { destination in
    switch destination {
    case .propertyFilter:
        PropertyFilter()
    case .student:
        Student()
    case .card:
        Card()
    case .rentalForm:
        Rentalform()
    case .flashLane:
        FlashLaneFeatures()
    case .easyPass:
        EasyPassFeatures()
    }
}
.hidden()

3. 优化点击逻辑

在图片的onTapGesture中,仅根据选中项的id设置跳转目标,避免同时修改多个状态:

.onTapGesture {
    selected = travel
    switch travel.id {
    case 0:
        destination = .propertyFilter
    case 1:
        destination = .student
    case 2:
        destination = .card
    case 3:
        destination = .rentalForm
    case 4:
        destination = .flashLane
    case 5:
        destination = .easyPass
    default:
        break
    }
}

完整修复代码

import SwiftUI

enum Destination {
    case propertyFilter, student, card, rentalForm, flashLane, easyPass
}

struct MainMenu: View {
    var columns = Array(repeating: GridItem(.flexible(), spacing: 15), count: 2)
    @State var selected: MainMenuData = data[0]
    @Namespace var namespace
    @State private var destination: Destination?
    
    var body: some View {
        NavigationView {
            ZStack {
                ScrollView(.vertical, showsIndicators: false) {
                    LazyVGrid(columns: columns, spacing: 25) {
                        ForEach(data) { travel in
                            VStack(alignment: .leading, spacing: 10) {
                                Image(travel.image)
                                    .resizable()
                                    .frame(width: 230, height: 260)
                                    .cornerRadius(15)
                                    .padding(.top, -65)
                                    .onTapGesture {
                                        selected = travel
                                        switch travel.id {
                                        case 0:
                                            destination = .propertyFilter
                                        case 1:
                                            destination = .student
                                        case 2:
                                            destination = .card
                                        case 3:
                                            destination = .rentalForm
                                        case 4:
                                            destination = .flashLane
                                        case 5:
                                            destination = .easyPass
                                        default:
                                            break
                                        }
                                    }
                                    .matchedGeometryEffect(id: travel.id, in: namespace)
                            }
                        }
                    }
                    .padding(.horizontal)
                    .padding(.top, 5)
                    .padding(.leading)
                }
                
                NavigationLink(item: $destination) { destination in
                    switch destination {
                    case .propertyFilter:
                        PropertyFilter()
                    case .student:
                        Student()
                    case .card:
                        Card()
                    case .rentalForm:
                        Rentalform()
                    case .flashLane:
                        FlashLaneFeatures()
                    case .easyPass:
                        EasyPassFeatures()
                    }
                }
                .hidden()
            }
            .toolbar {
                ToolbarItem(placement: .principal) {
                    Text("Main Menu")
                        .frame(width: 300, height: 10)
                        .foregroundColor(.black)
                        .font(.system(size: 30, weight: .medium))
                }
                ToolbarItem(placement: .navigationBarTrailing) {
                    Image(systemName: "bell")
                }
            }
        }
    }
}

struct MainMenu_Previews: PreviewProvider {
    static var previews: some View {
        MainMenu()
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 08:55:12