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

如何从网络Service类更新ViewModel中的@Published变量?

解决方案:从Service更新ViewModel的@Published变量

针对你的需求,有几种常用的实现方式,能让Service类精准更新GenerationViewModel中对应的@Published变量,以下是具体实现:

方式一:使用SwiftUI Binding

利用@Published变量自带的$语法获取Binding实例,将其传入Service,直接通过Binding修改对应状态。

Service 实现

class Service {
    private let fetchingBinding: Binding<Bool>
    
    init(fetchingBinding: Binding<Bool>) {
        self.fetchingBinding = fetchingBinding
    }
    
    func performRequest() {
        // 标记请求开始
        fetchingBinding.wrappedValue = true
        
        // 模拟异步网络请求
        DispatchQueue.global().asyncAfter(deadline: .now() + 2) {
            // 请求结束,更新状态
            self.fetchingBinding.wrappedValue = false
        }
    }
}

ViewModel 调用

func go() {  
    let service1 = Service(fetchingBinding: $fetching1)
    let service2 = Service(fetchingBinding: $fetching2)
    let service3 = Service(fetchingBinding: $fetching3)
    
    // 同时发起三个请求
    service1.performRequest()
    service2.performRequest()
    service3.performRequest()
}

方式二:使用闭包回调

如果不想依赖SwiftUI的Binding,可以通过闭包将状态更新逻辑传递给Service,请求状态变化时触发闭包更新ViewModel的变量。

Service 实现

class Service {
    private let updateStatus: (Bool) -> Void
    
    init(updateStatus: @escaping (Bool) -> Void) {
        self.updateStatus = updateStatus
    }
    
    func performRequest() {
        updateStatus(true)
        
        DispatchQueue.global().asyncAfter(deadline: .now() + 2) {
            self.updateStatus(false)
        }
    }
}

ViewModel 调用

func go() {  
    // 注意使用[weak self]避免循环引用
    let service1 = Service(updateStatus: { [weak self] status in
        self?.fetching1 = status
    })
    let service2 = Service(updateStatus: { [weak self] status in
        self?.fetching2 = status
    })
    let service3 = Service(updateStatus: { [weak self] status in
        self?.fetching3 = status
    })
    
    service1.performRequest()
    service2.performRequest()
    service3.performRequest()
}

方式三:使用Combine Publisher

如果项目中使用Combine框架,可以让Service通过Publisher输出状态,ViewModel订阅后更新对应变量,适合复杂的异步状态流转场景。

Service 实现

import Combine

class Service {
    private let statusSubject = PassthroughSubject<Bool, Never>()
    // 对外暴露只读的Publisher
    var statusPublisher: AnyPublisher<Bool, Never> {
        statusSubject.eraseToAnyPublisher()
    }
    
    func performRequest() {
        statusSubject.send(true)
        
        DispatchQueue.global().asyncAfter(deadline: .now() + 2) {
            self.statusSubject.send(false)
        }
    }
}

ViewModel 调用

import Combine

class GenerationViewModel: ObservableObject {
    @Published var fetching1:Bool = false
    @Published var fetching2:Bool = false
    @Published var fetching3:Bool = false
    
    // 存储订阅对象,防止被提前释放
    private var cancellables = Set<AnyCancellable>()

    func go() {  
        let service1 = Service()
        service1.statusPublisher
            .receive(on: DispatchQueue.main) // 切换到主线程更新UI状态
            .assign(to: \.fetching1, on: self)
            .store(in: &cancellables)
        
        let service2 = Service()
        service2.statusPublisher
            .receive(on: DispatchQueue.main)
            .assign(to: \.fetching2, on: self)
            .store(in: &cancellables)
        
        let service3 = Service()
        service3.statusPublisher
            .receive(on: DispatchQueue.main)
            .assign(to: \.fetching3, on: self)
            .store(in: &cancellables)
        
        service1.performRequest()
        service2.performRequest()
        service3.performRequest()
    }
}

各方式适用场景

  • Binding方式:简单直接,适合纯SwiftUI项目,依赖SwiftUI框架。
  • 闭包方式:无框架依赖,通用性强,适合UIKit与SwiftUI混合项目或跨模块场景。
  • Combine方式:适合复杂状态管理场景,能处理多步异步流的状态传递,需要引入Combine框架。

内容的提问来源于stack exchange,提问作者erotsppa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 20:33:39