SwiftUI @State属性selectedMaster点击无变化引发程序崩溃问题求助
问题根因
你触发崩溃的核心原因是 sheet(isPresented:) 的内容闭包会在视图渲染阶段提前捕获变量值,而非isPresented变为true时才读取最新状态。点击按钮同时修改两个@State属性时,SwiftUI会批量处理状态更新,存在isPresented已经触发sheet弹出,但selectedMaster还未完成赋值的时序问题,此时强制解包nil就会导致崩溃。
另外你当前通过索引遍历ForEach的写法存在潜在隐患:如果modelData.masters是动态更新的数组(比如Firebase异步拉取数据后变更),索引会发生错位,可能导致你赋值的selectedMaster不是实际点击的条目。
修复方案
1. 替换sheet调用方式
删除不需要的@State var isPresented = false变量,改用SwiftUI专为可选参数场景设计的sheet(item:)接口:该接口只有在绑定的可选值不为nil时才会弹出sheet,且会自动将解包后的非可选值传入内容闭包,完全规避强制解包风险。
2. 优化遍历逻辑
合并重复的列表渲染代码,直接遍历数组元素而非索引,避免动态数组的索引错位问题。
修复后完整代码参考
@EnvironmentObject var modelData: FirebaseModelData @State var selectionString = "" @State var selectedMaster: Master? var body: some View { ScrollView { VStack(spacing: 20.0) { LocationSelector() Searchbar() Text("Фильтр по услугам") .font(.title3) ServiceTypeSelection(selectionString: $selectionString) VStack { // 合并过滤逻辑,无需重复写两遍ForEach ForEach(modelData.masters.filter { master in selectionString.isEmpty || master.serviceTypes.contains(selectionString) }, id: \.self) { master in // 如果Master遵守Identifiable协议,可省略id参数直接写ForEach(filteredMasters) Button { selectedMaster = master } label: { MasterRow(master: master) } } .buttonStyle(PlainButtonStyle()) } } } .navigationBarTitle("") .navigationBarHidden(true) // 使用item版本的sheet,自动管理弹出状态,无需强制解包 .sheet(item: $selectedMaster) { master in MasterView(master: master) // iOS15+推荐用系统dismiss环境变量关闭sheet,无需自定义modalMode绑定:在MasterView中声明@Environment(\.dismiss) private var dismiss,需要关闭时调用dismiss()即可 .environment(\.modalMode, Binding( get: { false }, set: { if !$0 { selectedMaster = nil } } )) } }
如果你的Master类型没有遵守Hashable协议,无法使用\.self作为id,可以给Master添加Identifiable协议实现,增加唯一的id属性即可。
内容的提问来源于stack exchange,提问作者user15083246
相关产品推荐
相关产品推荐

