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

为什么SwiftUI中sheet在数据赋值前就打开引发崩溃?

问题原因

这个问题的本质是 SwiftUI 中 @State 属性的更新机制和 sheet(isPresented:) 构造器的内容闭包求值时机不匹配导致的,具体逻辑如下:

  • @State 属性的变更不是同步生效的。你在网络回调中先后对 dataToSend 和 openSheet 赋值,两个变更会被合并到当前 RunLoop 结束后的同一次视图渲染周期中才会正式生效,赋值后立即读取属性拿到的还是变更前的旧值。
  • sheet(isPresented:) 的内容闭包会在 isPresented 绑定值变为 true 的瞬间立即求值创建视图,不会等到本次渲染周期完成、所有 @State 变更都生效后再创建。这就导致闭包捕获到的 dataToSend 还是变更前的 nil,你声明的是隐式解包可选类型,直接访问就触发了崩溃。

你观察到的两个现象也能印证这个逻辑:

  1. 延迟1秒再修改 openSheet:此时已经经过了多个 RunLoop 周期,dataToSend 的变更早就完成生效,闭包读取到的就是非空值,不会崩溃。
  2. 给 dataToSend 设空数组初始值:此时不会触发解包崩溃,但 sheet(isPresented:) 的内容一旦创建就不会跟随 @State 变更自动刷新,所以即使后续 dataToSend 拿到了接口返回的正确数据,已经创建好的 MyView 也不会更新,一直显示初始的空数组。

解决方案

最优的解决方案是改用 sheet(item:) 构造器处理带数据的弹窗场景,完全避免手动管理两个关联状态的同步问题:

struct MyApp: App {
    // 改为普通可选类型,去掉隐式解包,不需要额外维护openSheet状态
    @State var dataToSend: [CustomClass]?
    var body: some Scene {
        WindowGroup {
            TabView {
                HomeView()
                SearchView()
                SettingsView()
            }
            // 使用sheet(item:)构造器,自动关联数据和弹窗状态
            .sheet(item: $dataToSend) { data in
                MyView(data: data)
            }
            .onOpenURL { url in
                ApiCall.getData(from: url) { dataFromApi in
                    // 只需要给dataToSend赋值即可,弹窗会自动弹出
                    self.dataToSend = dataFromApi
                }
            }
        }
    }
}

sheet(item:) 会自动在 item 不为 nil 时弹出弹窗,并且把非空的 item 直接传入内容闭包,完全不会出现空值问题。

内容的提问来源于stack exchange,提问作者swifthing

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 03:24:03