SwiftUI+MVVM架构下代理模式是否仍适用?Combine能否替代?
SwiftUI+MVVM中代理模式与Combine的实践解答
一、代理模式是否依然有效?
代理模式并没有过时,在SwiftUI+MVVM架构中依然可以使用,尤其是在需要多方法回调、复杂交互协议的场景下,它语义清晰,能明确定义组件间的交互契约。但在SwiftUI的响应式生态中,Combine框架提供了更简洁、更贴合的方案,能减少代理模式带来的模板代码(比如协议声明、弱引用维护、代理赋值等),让代码更简洁易读。
二、用Combine替代代理模式的实现
针对你当前的定时器更新场景,我们可以用Combine的PassthroughSubject或@Published来替代代理,实现响应式的状态传递:
改造后的Controller
import Combine class Controller { private var timer: Timer? // 用PassthroughSubject发送更新事件,适合一次性回调场景 let refreshSubject = PassthroughSubject<Double, Never>() init() { timer = Timer.scheduledTimer( timeInterval: 1.0, target: self, selector: #selector(refresh), userInfo: nil, repeats: true ) } @objc private func refresh() { // 模拟业务逻辑计算出的值 let updatedValue = 10.0 // 发送更新事件 refreshSubject.send(updatedValue) } }
改造后的ViewModel
import Combine class ViewModel: ObservableObject { private let controller = Controller() // 用于管理Combine订阅的生命周期,避免内存泄漏 private var cancellables = Set<AnyCancellable>() @Published var value: Double = 0.0 init() { // 订阅Controller的更新事件 controller.refreshSubject // 确保在主线程更新UI相关属性 .receive(on: DispatchQueue.main) // 将事件值绑定到ViewModel的@Published属性 .assign(to: \.value, on: self) // 保存订阅到cancellables中 .store(in: &cancellables) } }
视图部分无需修改
struct ExampleView: View { @ObservedObject var viewModel: ViewModel var body: some View { Text(viewModel.value.description) } }
如果Controller需要维护当前状态,也可以直接用@Published替代PassthroughSubject:
// 另一种Controller实现:用@Published维护状态 class Controller { private var timer: Timer? @Published var value: Double = 0.0 init() { timer = Timer.scheduledTimer( timeInterval: 1.0, target: self, selector: #selector(refresh), userInfo: nil, repeats: true ) } @objc private func refresh() { value = 10.0 // 直接更新@Published属性 } } // 对应的ViewModel订阅 class ViewModel: ObservableObject { private let controller = Controller() private var cancellables = Set<AnyCancellable>() @Published var value: Double = 0.0 init() { controller.$value .receive(on: DispatchQueue.main) .assign(to: \.value, on: self) .store(in: &cancellables) } }
三、Combine的其他核心用途
除了替代代理模式,Combine在SwiftUI开发中还有很多关键场景:
- 响应式状态绑定:结合
@Published和ObservableObject,实现视图与ViewModel的自动状态同步 - 异步流处理:比如网络请求、文件读取等异步操作,用Combine统一处理结果、错误和线程切换
- 用户输入优化:对搜索框输入做防抖(延迟请求)、节流(限制请求频率),提升用户体验
- 多数据流合并:同时监听多个状态变化,当所有条件满足时执行操作(比如表单所有字段验证通过后启用提交按钮)
- 生命周期管理:通过
store(in:)管理订阅生命周期,避免内存泄漏;用receive(on:)灵活切换线程
总结
代理模式可以继续使用,但Combine更适配SwiftUI的响应式编程模型,在简单回调、状态传递场景下能大幅简化代码。如果是复杂的多方法交互场景,代理模式的语义清晰性依然有优势,可以根据实际场景选择合适的方案。
内容的提问来源于stack exchange,提问作者inexcitus
相关产品推荐
相关产品推荐

