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

如何在不使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 09:03:12