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
相关产品推荐
相关产品推荐

