Лучший способ вызвать несколько запросов API в цикле for в RxSwift - PullRequest
0 голосов
/ 02 июня 2018

Я должен сделать несколько вызовов API (около 100), используя цикл for, и по завершении этого мне нужно завершить Observable.Я использую его следующим образом:

func getMaterialInfo(materialNo:[String]) -> Observable<[String: Material]>{
    return Observable.create({ (observable) -> Disposable in
        for (index,mat) in materialNo.enumerated(){
            // Pass the material number one by one to get the Material object
            self.getMaterialInfo(materialNo: mat).subscribe(onNext: { material in
                var materialDict: [String: Material] = [:]
                materialDict[material.materialNumber] = material
                observable.onNext(materialDict)
                if index == (materialNo.count-1){
                    observable.onCompleted()
                }
            }, onError: { (error) in
                observable.onError(error)
            }, onCompleted: {
            }).disposed(by: self.disposeBag)
        }
        return Disposables.create()
    })
}

Хотя цикл работает нормально и вызывается observable.onCompleted (), но метод вызывающего не получает его.Я называю это следующим образом:

private func getImage(materialNo:[String]){
    if materialNo.isEmpty {
        return
    }
    var dictMaterials = [String:String]()
    materialService.getMaterialInfo(materialNo: materialNo).subscribe(onNext: { (materials) in
        for (key,value) in materials{
            if (value.imageUrl != nil){
                dictMaterials[key] = value.imageUrl
            }
        }
    }, onError: { (error) in

    }, onCompleted: {
        self.view?.updateToolImage(toolImageList: dictMaterials)
    }, onDisposed: {}).disposed(by: disposeBag)
}

OnCompleted блок Rx не выполняется.Как я могу это исправить?

1 Ответ

0 голосов
/ 10 сентября 2018

Редактировать (5 марта)

Я повторно рассмотрел этот ответ, потому что я не уверен, что делал мой мозг, когда я писал пример кода ниже.Вместо этого я бы сделал что-то вроде этого:

func getMaterialInfo(materialNo: String) -> Observable<[String: Material]> {
    // ...
}

func getMaterialInfo(materialNumbers:[String]) -> Observable<[String: Material]>{
        let allObservables = materialNumbers
            .map { getMaterialInfo(materialNo: $0) }

        return Observable.merge(allObservables)
}

Исходный ответ

Из вашего кода я понимаю, что все отдельные вызовы getMaterialInfo выполняются одновременно.Исходя из этого, я бы переписал ваш метод getMaterialInfo(:[_]) для использования оператора .merge.

func getMaterialInfo(materialNo:[String]) -> Observable<[String: Material]>{
    return Observable.create({ (observable) -> Disposable in
        // a collection of observables that we haven't yet subscribed to
        let allObservables = materialNo
            .map { getMaterialInfo(materialNo: $0) }

        return Observable.merge(allObservables)
    }
    return Disposables.create()
}

Обратите внимание, что использование merge подписывается на все наблюдаемые одновременно, вызывая сеть 100запросы одновременно.Для последовательной подписки используйте concat вместо!

...