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

如何在SwiftUI的ObservableObject间传递属性?无需视图中转方案咨询

无需视图中转访问UserSettings的几种实现方式

方法一:依赖注入(推荐)

直接在TaskDialogViewModel初始化时传入UserSettings实例,让ViewModel直接持有依赖,既能直接访问属性,还能实时响应变化:

import Combine

@Observable final class TaskDialogViewModel {
    private let userSettings: UserSettings
    var taskDuration = 0
    private var cancellables = Set<AnyCancellable>()
    
    // 初始化时注入UserSettings
    init(userSettings: UserSettings) {
        self.userSettings = userSettings
        // 同步初始默认值
        self.taskDuration = userSettings.defaultTaskDuration
        
        // 监听UserSettings的变化,自动更新taskDuration
        userSettings.objectWillChange.sink { [weak self] in
            guard let self else { return }
            self.taskDuration = self.userSettings.defaultTaskDuration
        }.store(in: &cancellables)
    }
    
    func getDefaultTaskDuration() {
        taskDuration = userSettings.defaultTaskDuration
    }
}

在视图层注入ViewModel时,将EnvironmentObject的UserSettings传入:

struct Dialog: View {
    @EnvironmentObject var userSettings: UserSettings
    @StateObject private var model: TaskDialogViewModel
    
    init() {
        // 这里需要确保UserSettings已经被全局注入,或者通过环境获取后传入
        self._model = StateObject(wrappedValue: TaskDialogViewModel(userSettings: UserSettings()))
    }
    
    // 更稳妥的方式是在父视图中完成ViewModel的注入:
    // 父视图代码示例:
    // .environmentObject(UserSettings())
    // .environment(TaskDialogViewModel(userSettings: UserSettings()))
    
    var body: some View {
        HStack {
            // ...视图内容
        }
    }
}

方法二:单例模式访问UserSettings

如果UserSettings是全局唯一的,可以将其改为单例,让ViewModel直接调用:

final class UserSettings: ObservableObject {
    static let shared = UserSettings() // 全局单例
    @AppStorage("defaultTaskDuration") var defaultTaskDuration: Int = 1500
    //... 其他AppStorage属性
}

ViewModel中直接访问单例:

import Combine

@Observable final class TaskDialogViewModel {
    var taskDuration = 0
    private var cancellables = Set<AnyCancellable>()
    
    init() {
        // 监听单例的变化
        UserSettings.shared.objectWillChange.sink { [weak self] in
            self?.taskDuration = UserSettings.shared.defaultTaskDuration
        }.store(in: &cancellables)
    }
    
    func getDefaultTaskDuration() {
        taskDuration = UserSettings.shared.defaultTaskDuration
    }
}

这种方式实现简单,但ViewModel与UserSettings耦合度高,不利于单元测试(难以模拟UserSettings)。

方法三:ViewModel直接使用@AppStorage

因为defaultTaskDuration本身存储在AppStorage中,ViewModel可以直接通过@AppStorage访问,无需经过UserSettings中转:

@Observable final class TaskDialogViewModel {
    @AppStorage("defaultTaskDuration") private var storedDefaultDuration: Int = 1500
    var taskDuration = 0
    
    func getDefaultTaskDuration() {
        taskDuration = storedDefaultDuration
    }
}

这种方式最直接,适合只需要单个AppStorage属性的场景;如果UserSettings管理多个关联属性,建议优先使用前两种方法。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 14:47:19