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

SwiftUI 弹出sheet时已赋值的selectedTask State为nil是什么原因?

SwiftUI sheet读取可选State为nil的解决方案

问题原因

sheet(isPresented:)的内容闭包会在父视图首次渲染时完成值捕获,不会等到sheet实际弹出时再读取最新的@State变量。你点击列表项时才给selectedTask赋值,此时已经完成捕获的闭包拿到的还是最初的nil值,强制解包就会崩溃。

推荐解决方案:使用sheet(item:)构造器

这是Apple官方为可选值触发sheet场景设计的API,无需手动管理显示用的Bool变量,自动监听可选值状态,值非空时自动弹出sheet,且闭包内直接拿到解包后的非空值:

代码修改步骤:

  1. 删掉不需要的showComputedTaskSheet状态变量
  2. 修改onTapGesture逻辑,仅需给selectedTask赋值
  3. 替换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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.10 19:27:04