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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 11:05:35