SwiftUI 弹出sheet时已赋值的selectedTask State为nil是什么原因?
SwiftUI sheet读取可选State为nil的解决方案
问题原因
sheet(isPresented:)的内容闭包会在父视图首次渲染时完成值捕获,不会等到sheet实际弹出时再读取最新的@State变量。你点击列表项时才给selectedTask赋值,此时已经完成捕获的闭包拿到的还是最初的nil值,强制解包就会崩溃。
推荐解决方案:使用sheet(item:)构造器
这是Apple官方为可选值触发sheet场景设计的API,无需手动管理显示用的Bool变量,自动监听可选值状态,值非空时自动弹出sheet,且闭包内直接拿到解包后的非空值:
代码修改步骤:
- 删掉不需要的
showComputedTaskSheet状态变量 - 修改onTapGesture逻辑,仅需给
selectedTask赋值 - 替换sheet的构造方法为item版本
修改后的完整核心代码如下:
struct TasksTabView: View { // 删掉原来的showComputedTaskSheet变量 @State var selectedTask: OrderTaskCheck? var body: some View { VStack(alignment: .leading) { List { ForEach(Array(tasks.enumerated()), id:\.1.title) { (index, task) in VStack(alignment: .leading, spacing: 40) { HStack(spacing: 20) { PillForRow(index: index, task: task) }.padding(.bottom, 30) }.onTapGesture { // 仅需赋值,sheet会自动弹出 self.selectedTask = task } } } }.listStyle(SidebarListStyle()) } // 替换为item版本的sheet构造器 .sheet(item: $selectedTask) { task in // 此处task为自动解包的非空值,无需强制解包 showScreen(task: task) } .onAppear { UITableView.appearance().backgroundColor = .white } }
兼容方案(保留isPresented写法)
如果必须保留原来的isPresented逻辑,可以给sheet添加id()修饰符,指定id为selectedTask,当selectedTask变化时会强制重建sheet,重新捕获最新的状态值:
.sheet(isPresented: $showComputedTaskSheet) { showScreen(task: self.selectedTask!) } .id(selectedTask) // 新增这行即可
注意:该方案仍存在强制解包崩溃的风险,优先选择item版本的构造器。
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

