首页 > 解决方案 > 使用 SwiftUI/Combine,如何避免在 ViewModel 中放置可取消项

问题描述

我一直使用 RxSwift 将 DisposeBag 放在 MVVM 中的 ViewController 中,就像它在本主题中所说的那样:

在 iOS 上,对于 MVVM 中的 DisposeBag,可以放在 ViewModel 中吗?

但是使用组合,由于 View 是一个结构并且可取消的不能放在其中,我被困在解决方案中。

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

或者,在 SwiftUI/Combine 中,没有选择在 VM 中放置可取消项。

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

视图模型


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) €&quot;
            }.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,
                        maxWidth: .infinity,
                        alignment: .topLeading)
                .padding()
                Button(action: self.viewModel.addToPortfolio, label: {
                    Text("Add to portfolio")
                        .foregroundColor(.white)
                        .frame(minWidth: 0,
                                maxWidth: .infinity,
                                maxHeight: 30,
                                alignment: .center)
                        .background(Color.blue)
                        .cornerRadius(5)
                }).padding()
                Spacer()
            }
        }.frame(alignment: .leading)
        .onAppear(perform: self.viewModel.onAppear)
    }
}

标签: mvvmswiftuireactive-programmingrx-swiftcombine

解决方案


你搜索的是什么?我无法测试它我不知道您使用的是什么库

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) €&quot; }
//            .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)
    }
}

推荐阅读