使用SwiftUI /合并,如何避免将可取消对象放入ViewModel

问题描述

我总是使用RxSwift将disposeBag放在MVVM的ViewController中,就像本主题中所说的那样:

On iOS,for the DisposeBag in MVVM,can it be placed in ViewModel?

但是使用Combine时,由于View是一个结构,并且不能在其中放置可取消的对象,因此我只能解决问题。

如何在合并中管理View和VM之间的订阅而又不可以在viewmodel中取消添加

或者也许,在SwiftUI / Combine中,没有选择将取消对象放置在VM中。

在SiwftUI / Combine中有一个实现示例:

viewmodel


class Equityviewmodel: ObservableObject {
    
    @Injected private var api: AlphaVantageAPI
    
    private var cancellables = Set<AnyCancellable>()
    private let code: String
    @Published private var result: Quote?
    @Published var price: String = ""
    
    init(code: String) {
        self.code = code
        self.$result
            .map {
                return "\($0?.price ?? 0) €"
            }.assign(to: &$price)
    }
    
    
    func addToPortfolio(){
        
    }
    
    func onAppear() {
        self.api.quote(symbol: self.code).share()
            .sink { completion in }
                receiveValue: { quote in
                    self.result = quote.quote
                }
            .store(in: &cancellables)
    }
    
}

视图

struct EquityView: View {
    
    @Observedobject  var viewmodel: Equityviewmodel
    
    init(viewmodel: Equityviewmodel) {
        self.viewmodel = viewmodel
    }
    
    var body: some View {
        ZStack {
            Color("primary").edgesIgnoringSafeArea(.all)
            vstack {
                Text("Stock Price")
                    .foregroundColor(.white)
                    .frame(minWidth: 0,maxWidth: .infinity,alignment: .topLeading)
                    .padding()
                HStack {
                    Text(self.viewmodel.price)
                        .foregroundColor(.white)
                    Text("+4.75 %")
                        .foregroundColor(.white)
                        .padding(.leading,20)
                }.frame(minWidth: 0,alignment: .topLeading)
                .padding()
                Button(action: self.viewmodel.addToPortfolio,label: {
                    Text("Add to portfolio")
                        .foregroundColor(.white)
                        .frame(minWidth: 0,maxHeight: 30,alignment: .center)
                        .background(Color.blue)
                        .cornerRadius(5)
                }).padding()
                Spacer()
            }
        }.frame(alignment: .leading)
        .onAppear(perform: self.viewmodel.onAppear)
    }
}

解决方法

这就是您搜索的内容吗?我无法测试,我不知道您使用的是什么库

class EquityViewMode: ObservableObject {
//    @Injected private var api: AlphaVantageAPI
    
    var pricePublisher: AnyPublisher<String,Never>
    @Published var price: String = ""

    init(){
        
//         init your publisher like
//        pricePublisher = self.api.quote(symbol: self.code)
//            .share()
//            .map { "\($0?.price ?? 0) €" }
//            .eraseToAnyPublisher()

}


struct EquityView: View {

    @ObservedObject var viewModel: EquityViewModel
    var handle: AnyCancellable? = nil

    init(m:EquityViewMode) {
        viewModel = m
        handle = m.pricePublisher.assign(to: \.price,on: self.viewModel)
    }

    var body: some View{
        Text(viewModel.price)
    }
}