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

SwiftUI中如何通过SheetViewModel更新MainViewModel的Published属性?

问题解决:通过SheetViewModel更新MainViewModel的用户名

错误原因解析

你遇到的Cannot convert value of type 'Binding<String>' to expected argument type 'Published<String>.Publisher'错误,本质是混淆了SwiftUI Binding和Combine Publisher的用法:

  • $viewModel.username是Binding<String>类型,用于视图和属性的双向绑定;
  • 而Combine的assign(to:)方法需要的是Published属性对应的Publisher,或者通过键路径直接绑定到ObservableObject的属性。
    同时,你的SheetViewModel中bindEvents()方法未被调用,导致按钮点击后不会触发usernameUpdated事件流。

修复方案

1. 完善SheetViewModel的事件绑定逻辑

在SheetViewModel的初始化方法中调用bindEvents(),确保按钮点击能触发用户名更新的事件流:

final class SheetViewModel: ObservableObject {
    struct Event {
        let updateUsernameButtonTapped = PassthroughSubject<Void, Never>()
        let usernameUpdated = PassthroughSubject<String, Never>()
    }

    let event = Event()
    private var cancellables = Set<AnyCancellable>()

    // 初始化时自动绑定事件
    init() {
        bindEvents()
    }

    private func bindEvents() {
        event.updateUsernameButtonTapped
            .map { "Sam" }
            .sink { [weak self] name in
                self?.event.usernameUpdated.send(name)
            }
            .store(in: &cancellables)
    }
}

2. 正确订阅事件到MainViewModel

在MainView的sheet闭包中,将SheetViewModel的usernameUpdated事件绑定到MainViewModel的username属性,同时将订阅保存到SheetViewModel的cancellables集合中,避免订阅提前失效:

struct MainView: View {
    @ObservedObject private var viewModel: MainViewModel
    @State private var isShowingBottomSheet = false

    var body: some View {
        VStack {
            Text("Hello \(viewModel.username)")
                .font(.title)

            Button("Show bottom sheet") {
                isShowingBottomSheet = true
            }
            .sheet(isPresented: $isShowingBottomSheet) {
                let sheetViewModel = SheetViewModel()
                // 订阅事件并更新MainViewModel的username
                sheetViewModel.event.usernameUpdated
                    .assign(to: \.username, on: viewModel)
                    .store(in: &sheetViewModel.cancellables)

                SheetView(viewModel: sheetViewModel)
                    .presentationDetents([.fraction(0.15), .medium])
            }
        }
    }

    init(viewModel: MainViewModel) {
        self.viewModel = viewModel
    }
}

可选:用sink手动赋值(更直观)

如果你习惯手动处理赋值逻辑,可以将订阅部分替换为:

sheetViewModel.event.usernameUpdated
    .sink { [weak viewModel] newUsername in
        viewModel?.username = newUsername
    }
    .store(in: &sheetViewModel.cancellables)

效果验证

修改完成后,点击Sheet中的"Change Name"按钮,MainView中的用户名会从"John"更新为"Sam",符合你通过ViewModel事件流更新数据的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 08:30:49