SwiftUI中@State变量首次点击按钮未正确赋值问题
SwiftUI 首次点击按钮无法正确赋值@State变量的问题
问题:为每个CourseClub对象设置按钮,点击时将@State变量watchingClub赋值为当前遍历的对象,再打开详情视图。但首次点击任意按钮时,变量无法正确赋值,详情视图显示初始空值;后续点击按钮正常工作,再次点击首次点击的按钮也能正常赋值。
相关代码
DetailView 代码
var section: KursSection @EnvironmentObject var vm: TimetableViewModel var stundenkurse = [CourseStunden]() @State var showClubPanel = false @State var watchingClub = CourseClub(name: "", image: "", sorting: "", dates: [CourseDate(id: "", day: 1, time: Date.now, room: "", startDate: Date.now)]) var body: some View { ZStack{ ScrollView { cover sections } .ignoresSafeArea() .background() .sheet(isPresented: $showClubPanel) { CourseDetailView(course: watchingClub) .presentationDetents([.medium, .large]) } } } var sections: some View { VStack(alignment: .leading, spacing: 12){ ForEach(section.sectionsClub){ stufe in Text(stufe.section.uppercased()) .font(.footnote.weight(.semibold)) .padding(.vertical) if(stufe.array.count == 0){ Text("Momentan keine Termine für diesen Kurs") .font(.footnote) } else { ForEach(stufe.array){ kurs in Button{ DispatchQueue.main.async { self.watchingClub = kurs showClubPanel = true } } label: { HStack{ Text(kurs.name) .padding() .frame(maxWidth: .infinity) .background(.ultraThinMaterial) .cornerRadius(20) } } } } } } .frame(maxWidth: .infinity, alignment: .leading) .offset(y: 100) .padding(.bottom, 200) .padding(.horizontal, 20) }
CourseClub 结构体代码
struct CourseClub: Identifiable { var id = UUID() let name: String let image: String let sorting: String var dates = [CourseDate]() var sortingInt = 0 }
主视图导航代码
ScrollView{ ForEach(sectionData){ section in Button{ self.section = section shouldNavigate.toggle() } label: { KursSectionItem(title: section.title, subtitle: section.subtitle, img: section.img) } } .navigationTitle("Kursübersicht") } .onAppear(){ sectionData = [ KursSection(title: "Erwachsene", subtitle: "Alle Tanzkurse für Erwachsene", img: "//...", sectionsClub: [KursSectionClub(section: "Tanzcards", array: vm.coursesClubErwachsene)]), ] // ... }
解决方案
问题核心:首次展示sheet时,SwiftUI会提前捕获watchingClub的初始值,后续修改变量时,sheet不会自动更新内容;后续点击正常是因为sheet已存在,状态更新能同步到视图。
推荐修复方案:使用sheet(item:)替代sheet(isPresented:)
利用CourseClub的Identifiable特性,直接绑定可选对象,让sheet根据对象变化自动更新,避免提前捕获值的问题:
- 修改
watchingClub为可选类型:
@State var watchingClub: CourseClub? // 移除初始空值,改为可选
- 替换sheet的绑定方式:
.sheet(item: $watchingClub) { club in CourseDetailView(course: club) .presentationDetents([.medium, .large]) }
- 简化按钮点击逻辑,无需
showClubPanel变量:
Button{ self.watchingClub = kurs // 直接赋值,sheet会自动弹出 } label: { // 原label内容保持不变 }
这种方式完全符合SwiftUI的状态管理逻辑,代码更简洁可靠,sheet(item:)会在watchingClub不为nil时自动弹出视图,为nil时自动关闭,且每次都会使用最新的对象创建详情视图。
备选修复方案:强制延迟刷新(不推荐)
若必须保留isPresented方式,可通过延迟刷新确保变量赋值完成后再弹出sheet,但依赖视图刷新时机,稳定性较差:
Button{ self.watchingClub = kurs showClubPanel = false DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) { showClubPanel = true } } label: { // 原label内容保持不变 }
内容的提问来源于stack exchange,提问作者Toby
相关产品推荐
相关产品推荐

