【问题标题】:RxSwift: how to get rid of callback hells of subscribe events and network request?RxSwift:如何摆脱订阅事件和网络请求的回调地狱?
【发布时间】:2019-04-28 03:45:42
【问题描述】:

RxSwift:如何摆脱订阅事件和网络请求的回调地狱?

我是一个新的 Swifter,这是我新公司的代码。

以下代码非常连贯。

逻辑很简单。 BoutiqueOutput 有一个 requestCommand,即 PublishSubject。它用于做一些刷新的事情(一次又一次地请求网络)。

回调地狱就在其中。网络层 Moya 以 RxSwift 的方式使用。

RxSwift 新手,我不知道如何很好地重构它。

如何正确使用filter/map/combine操作符?

这是用 RxSwift 封装的模型


import RxSwift
import RxCocoa
import RxDataSources
import MJRefresh
import Moya
import MoyaMapper


// this is the Moya Network Provider
let Provider = MoyaProvider<Router>(endpointClosure: EndpointClosure, requestClosure: requestClosure, plugins: [networkPlugin, MoyaMapperPlugin(NetParameter())], trackInflights: false)


struct BoutiqueOutput: OutputRefreshProtocol {

    var refreshStatus = Variable<RefreshStatus>(.none)

    let sections: Driver<[CategoryLeftSection]>

    let requestCommand = PublishSubject<Bool>()
    init(sections: Driver<[CategoryLeftSection]>) {
        self.sections = sections
    }
}


class CategoryViewModel: NSObject {

    let vmDatas = Variable<[ParentItem]>([])

    func transform() -> BoutiqueOutput {

        let tempSections = vmDatas.asObservable().map({ (sections) -> [CategoryLeftSection] in
            return [CategoryLeftSection(items: sections)]
        }).asDriver(onErrorJustReturn: [])

        let output = BoutiqueOutput(sections: tempSections)
        output.requestCommand.subscribe(onNext:{[weak self] _ in
            guard let self = self else { return }
            Provider.rx.cacheRequest(.baseUIData).subscribe( onNext:{ result in
                // do some UI 
                if result.statusCode == 200 || result.statusCode == 230 {
                    // do something business
                } 

            }).disposed(by: self.rx.disposeBag)
        }).disposed(by: rx.disposeBag)
        return output
    }
}


这就是模型的应用方式

private var vmOutput: BoutiqueOutput?


override func viewDidLoad() {
        super.viewDidLoad()
        self.vmOutput = viewModel.transform()
        boundTableViewData()
    // ...
}


private func boundTableViewData() {

    let dataSource = RxTableViewSectionedReloadDataSource<CategoryLeftSection>( configureCell: { [weak self] ds, tv, ip, item in
     // ...
     }


  vmOutput!.sections.asDriver().drive(self.leftMenuTableView.rx.items(dataSource: dataSource)).disposed(by: rx.disposeBag)

     // ...

    vmOutput!.requestCommand.onNext(true)

}



private func requestErrorRefresh() {
     // ...
     if isNetworkConnect {
           boundTableViewData()
           vmOutput!.requestCommand.onNext(true)
     }
}


private func noNetworkRefresh() {
     // ...
     if isNetworkConnect {
           boundTableViewData()
           vmOutput!.requestCommand.onNext(true)
     }
}

【问题讨论】:

    标签: swift rx-swift


    【解决方案1】:

    我使用combineLatest 运算符来解决这个问题。

    代码如下:

    let output = BoutiqueOutput(sections: temp_sections)
    Observable.combineLatest(output.requestCommand, Provider.rx.cacheRequest(.baseUIData)).subscribe({  [weak self]  ( result: Event<(Bool, Response)>) in
                guard let self = self else { return }
                switch result{
                case .next(let response):
                    // do some UI 
                    if result.statusCode == 200 || result.statusCode == 230 {
                         // do something business
                    } 
                default:
                    break
                }
            }).disposed(by: rx.disposeBag)    
    

    combineLatest:只要任何可观察序列产生一个元素,就将指定的可观察序列合并为一个可观察的元组序列。

    很高兴将两个不相关的事件结合在一起,做一些共同的事情。

    顺便说一句:我想了两天,不知道如何解决。和我 系统地列出并发布在这里,一段时间后,我想通了 出去。有趣的经历。

    【讨论】: