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

SwiftUI:如何通过UI(如Picker)更新ObservableObject中的Published值

更新说明:
本问题已解决。正确做法是通过投影ObservableObject来获取Binding,例如使用$options.refreshRate。

问题简述

如何让SwiftUI的Picker(或其他依赖本地Binding的API)立即更新我的ObservedObject/EnvironmentObject?以下是详细背景...

应用场景

我在开发每一款SwiftUI应用时都会遇到这样的需求:

  • 创建一个存储用户偏好的类(命名为Options),并将其设为ObservableObject。
  • 所有需要被订阅的设置都用@Published标记。
  • 使用该设置的视图通过@ObservedObject或@EnvironmentObject引入并订阅变更。

这套流程运行良好,但我始终面临一个问题:如何通过UI更新这些设置?通常我的做法如下:

  • 创建如OptionsPanel这样的SwiftUI视图,用于驱动Options类,让用户选择偏好设置。
  • 假设有一个用枚举定义的选项:
enum RefreshRate {
    case low, medium, high
}

自然地,我会选择SwiftUI的Picker来设置这个选项,但Picker的API要求选择参数必须是Binding。这就是问题所在...

核心问题

为了让Picker正常工作,我通常会使用一个本地Binding,但实际上我并不关心这个本地值,而是希望选择变更后能立即向整个应用广播新值。ObservableObject(即Options类)本身可以很好地实现广播,但当前只是更新本地Binding,我需要找到每次变更时都能立即将Picker状态同步到ObservableObject的方法。

非理想解决方案

最初的思路理论上可行,但遇到了阻碍:

在SwiftUI视图中,我没有用最简单的@State来创建Binding,而是尝试用另一种初始化方式:

// 原本的写法...
@ObservedObject var options: Options
@State var refreshRate: RefreshRate = .medium

// 尝试的写法...
@ObservedObject var options: Options
var refreshRate: Binding<RefreshRate>(
    get: { self.options.refreshRate },
    set: { self.options.refreshRate = $0 }
) 

理论上这很棒!本地Binding直接关联到ObservableObject,Picker的所有变更都会立即广播到整个应用。

但这段代码无法运行,会报错:

Cannot use instance member 'options' within property initializer; property initializers run before 'self' is available

于是我用了一个糟糕的变通方案,虽然能运行,但架构很差:

让Options类提供一个静态的shared单例实例,然后在选项面板视图中这样写:

@ObservedObject var options: Options = .shared // <-- 仍需保留以让SwiftUI监听更新
var refreshRate: Binding<RefreshRate>(
    get: { Options.shared.refreshRate },
    set: { Options.shared.refreshRate = $0 }
) 

在这个场景下这确实能运行,因为我只需要一个实例,只要始终引用这个单例就没问题,但这种架构并不合理。

那么...*有没有更好的解决方案?*这似乎是所有应用都会遇到的场景,肯定有更优的实现方式。

(我知道有人用.onDisappear来同步本地状态到ObservableObject,但这也不理想,因为我需要即时更新整个应用的状态。)


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 20:30:42