retryWhen не переписывает источник, как ожидалось - PullRequest
0 голосов
/ 29 августа 2018

Я пишу логику для проверки состояния объекта каждые t секунд до его завершения. Я решил использовать оператор retryWhen.

getObjectStatus(someObject: someObjectInstance)
    .flatMap { someObject -> Observable<SomeObject> in
        if someObject.status == .notProcessed {
            return .error(SomeObjectNotProcessed())
        } else {
            return .just(someObject)
        }
    }
    .retryWhen { errors -> Observable<Void> in
        let retry = errors.enumerated().flatMap { retryCount, error -> Observable<Void> in
            guard retryCount < statusRequestCount else {
                print("The maximum number of request has been reached.")
                return .error(error)
            }

            if error is SomeObjectNotProcessed {
                return Observable.just(Void())
                        .delay(statusRequestDelay, scheduler: BackgroundScheduler.instance)
            } else {
                return .error(error)
            }
        }

        return retry
    }
    .subscribeOn(BackgroundScheduler.instance)
    .observeOn(MainScheduler.instance)
    .subscribe(onNext: { [weak self] someObject in
        self?.someObjectProcessingSucceeded()
    }, onError: { [weak self] error in
        self?.someObjectProcessingFailed(error: error)
    })
    .disposed(by: disposeBag)

Где метод getObjectStatus создает запрос к серверу.

Теперь проблема в том, что с этим кодом каждые t секунд (statusRequestDelay на самом деле) я не делаю запрос к серверу. Каждые t секунд он возвращает один и тот же экземпляр someObject. Если я заменю getObjectStatus на:

Observable.just(Void())
    .flatMap { _ in self.getObjectStatus(someObject: someObjectInstance) }

работает отлично, что означает, что он делает запрос к серверу каждые t секунд. Похоже, первый, оригинальный Observable не повторяется.

1 Ответ

0 голосов
/ 31 августа 2018

Проблема в том, как написана ваша функция getObjectStatus. По-видимому, он возвращает .just или некоторую другую наблюдаемую величину, которая фактически не повторяет сетевой вызов. Не видя этот код, я не могу дать однозначного ответа.

Однако обратите внимание:

func getObjectStatus(someObject: Int) -> Observable<SomeObject> {
    var count = 0
    return Observable.create { observer in
        print("called getObjectStatus")
        if count < 3 {
            observer.onNext(SomeObject(status: .notProcessed))
            observer.onCompleted()
            count += 1
        }
        else {
            observer.onNext(SomeObject(status: .processed))
            observer.onCompleted()
        }
        return Disposables.create()
    }
}

Использование вышеприведенного с вашей цепью приведет к тому, что "selectedObjectStatus" будет напечатан 3 раза.

В то время как:

var count = 0
func getObjectStatus(someObject: Int) -> Observable<SomeObject> {
    print("called getObjectStatus")
    if count < 3 {
        count += 1
        return Observable.just(SomeObject(status: .notProcessed))
    }
    else {
        return Observable.just(SomeObject(status: .processed))
    }
}

Не будет.

Разница здесь в том, что в последнем случае .just(SomeObject(status: .notProcessed)) - это то, на что подписывается подписка, поэтому он каждый раз возвращает одно и то же.

Закрытие вызова в flatMap работает, потому что это .just(Void()), на который повторно подписывается, что означает, что содержимое flatMap вызывается снова.

...