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?
2. 统一管理NavigationLink
将所有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
相关产品推荐
相关产品推荐

