如何使用SwiftUI新@Observable宏构建Combine管道?
使用@Observable宏构建的类搭建Combine管道的方案
针对@Observable类无法直接通过$属性名获取Combine Publisher的问题,有两种可行的解决方案,同时也可以保留原有的ObservableObject方案作为替代。
方案一:利用Observation框架的Combine扩展
@Observable宏生成的类自动遵循Observation.Observable协议,Combine框架为该协议提供了扩展方法,可以通过publisher(for:)获取特定属性的变化Publisher。
修改后的代码示例:
import SwiftUI import Combine @Observable private class WhiteSpaceTrimmer { var incomingText: String var outgoingText: String private var cancellables = Set<AnyCancellable>() // 存储Combine订阅,防止被销毁 init(initialText: String = "") { self.incomingText = initialText self.outgoingText = initialText // 获取incomingText的变化Publisher self.publisher(for: \.incomingText) .debounce(for: .seconds(0.1), scheduler: DispatchQueue.main) .map { $0.trimmingCharacters(in: .whitespaces) } .assign(to: \.outgoingText, on: self) .store(in: &cancellables) } } // ContentView无需修改,保持原代码即可 struct ContentView: View { @State private var trimmer = WhiteSpaceTrimmer(initialText: " Hello World ") var body: some View { VStack{ TextField("Input", text: $trimmer.incomingText) .textFieldStyle(.roundedBorder) HStack { Text("Raw Input: \"\(trimmer.incomingText)\"") Spacer() } HStack { Text("Cleaned Output: \"\(trimmer.outgoingText)\"") Spacer() } } .padding() } }
关键注意点:
- 必须导入
Combine框架 - 需要维护
Set<AnyCancellable>来存储订阅,否则Combine管道会在初始化完成后立即被销毁 publisher(for: \.属性名)方法会发出该属性每次变更后的最新值,行为与@Published的$属性名一致
方案二:属性观察者+定时器替代Combine(轻量场景)
如果你的需求仅涉及简单的防抖或值转换,也可以不依赖Combine,直接用属性观察者配合定时器实现:
@Observable private class WhiteSpaceTrimmer { var incomingText: String { didSet { // 每次输入时重置防抖定时器 debounceTimer?.invalidate() debounceTimer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: false) { [weak self] _ in guard let self else { return } self.outgoingText = self.incomingText.trimmingCharacters(in: .whitespaces) } } } var outgoingText: String private var debounceTimer: Timer? init(initialText: String = "") { self.incomingText = initialText self.outgoingText = initialText.trimmingCharacters(in: .whitespaces) } }
这种方式无需引入Combine,代码更轻量,但处理复杂的数据流操作(如多源合并、过滤、链式转换等)时,Combine的可读性和扩展性会更有优势。
保留ObservableObject的选择
如果你的Combine管道逻辑复杂,继续使用ObservableObject + @Published确实是更直接的方案。目前Apple并未弃用ObservableObject,该方案可以正常使用,直到@Observable的Combine集成进一步完善。
内容的提问来源于stack exchange,提问作者Curious Jorge
相关产品推荐
相关产品推荐

