如何在不使用ObservableObject的SwiftUI视图中使用Combine?
问题描述
希望将原本放在ObservableObject类型ViewModel中的Publisher直接置于SwiftUI视图内部,要求完全不使用ObservableObject、@StateObject或ViewModel,尝试在View结构体的init方法中使用Combine框架,但代码无法运行:
struct ContentView: View { @State private var boolOne = false @State private var boolTwo = false @State private var boolsBoth = false private var cancellables = Set<AnyCancellable>() init() { // dummy publisher that doesn't nothing, not the point of the question Publishers.CombineLatest($boolOne, $boolTwo) .receive(on: RunLoop.main) .map { boolOne, boolTwo -> Bool in return true } .removeDuplicates() .sink(receiveValue: { value in boolsBoth = value }) } var body: some View { VStack { Text("Hello, world!") } .padding() } }
报错信息:Generic struct 'CombineLatest' requires that 'Binding' conform to 'Publisher'
解决方案
核心问题分析
$boolOne是Binding<Bool>类型,并非Combine的Publisher,因此无法直接传入CombineLatest。需要将Binding转换为Publisher,同时处理订阅的生命周期和@State变量的正确访问。
修改后的代码
struct ContentView: View { @State private var boolOne = false @State private var boolTwo = false @State private var boolsBoth = false private var cancellables = Set<AnyCancellable>() init() { Publishers.CombineLatest($boolOne.publisher, $boolTwo.publisher) .receive(on: RunLoop.main) .map { boolOne, boolTwo -> Bool in return boolOne && boolTwo // 替换为实际业务逻辑 } .removeDuplicates() .sink(receiveValue: { value in self._boolsBoth.wrappedValue = value }) .store(in: &cancellables) // 保存订阅,避免立即销毁 } var body: some View { VStack { Toggle("Bool One", isOn: $boolOne) Toggle("Bool Two", isOn: $boolTwo) Text("Both are true: \(boolsBoth.description)") } .padding() } }
关键修改点
- Binding转Publisher:通过
$boolOne.publisher和$boolTwo.publisher将Binding转换为Combine支持的Publisher,这样就能参与CombineLatest的组合操作。 - 保存订阅生命周期:订阅创建后必须调用
.store(in: &cancellables),将订阅实例存入集合中,否则订阅会被立即释放,无法响应后续的数值变化。 - 正确访问@State变量:在
init中直接给boolsBoth赋值会报错,因为@State的包装器在视图初始化阶段尚未完成配置,需要通过_boolsBoth.wrappedValue直接访问底层存储的值。
内容的提问来源于stack exchange,提问作者user1302387
相关产品推荐
相关产品推荐

