首页 > 解决方案 > 需要帮助来理解 RxSwift 中重试和共享的概念

问题描述

retry()所以我无法真正share()理解RxSwift.Observable. 好吧,我想我可能对它们是什么有一些想法,但某些案例让我质疑我对它们的理解。所以我有这个测试用例:

func testOnViewDidLoad_WhenError_ShouldRetry3Times() throws {
    var actualRetryCount = 0
    let creditCardInfoProvider: CreditCardInfoProviderBlock = {
        actualRetryCount += 1
        return .error(RxCocoaURLError.unknown)
    }
    
    let viewModel = createViewModel(creditCardInfoProvider: creditCardInfoProvider)
    
    viewModel.onViewDidLoad()
    
    XCTAssertEqual(3, actualRetryCount)
}

课程是:

final class PaymentInfoViewModel {
    private(set) lazy var populateData = creditCardsRelay.asDriver()
    private let creditCardsRelay = BehaviorRelay<[CreditCardInfo]>(value: [])

    private let creditCardInfoProvider: () -> Observable<[CreditCardInfo]>
    init(creditCardInfoProvider: @escaping () -> Observable<[CreditCardInfo]>) {
        self.creditCardInfoProvider = creditCardInfoProvider
    }

    func onViewDidLoad() {
        .....
    }
}

我的第一个问题是:这是怎么回事?

func onViewDidLoad() {
    Observable.just(())
        .flatMapLatest { [weak self] () -> Observable<[CreditCardInfo]> in
            guard let `self` = self else { return .empty() }
            return self.creditCardInfoProvider() }
        .retry(3)
        .do(onError: { [weak self] in
            self?.handleErrors(error: $0)
        })
        .bind(to: creditCardsRelay)
        .disposed(by: disposeBag)
}

但这不是(结果是一个。这意味着它没有被重试。)?

func onViewDidLoad(){
    creditCardInfoProvider()
        .retry(3)
        .do(onError: { [weak self] in
            self?.handleErrors(error: $0)
        })
        .bind(to: creditCardsRelay)
        .disposed(by: disposeBag)
}

我的第二个问题是:我有另一个继电器将由相同的功能触发。所以我将它重构为一个共享的 observable,如下所示:

func onViewDidLoad() {
    let sharedCardProvider = Observable.just(())
        .flatMapLatest { [weak self] () -> Observable<[CreditCardInfo]> in
            guard let `self` = self else { return .empty() }
            return self.creditCardInfoProvider() }
        .retry(3)
        .do(onError: { [weak self] in
            self?.handleErrors(error: $0)
        }).share()
        
    sharedCardProvider
        .bind(to: creditCardsRelay)
        .disposed(by: disposeBag)
    
    sharedCardProvider
        .map { !$0.isEmpty }
        .bind(to: addCreditCardButtonHiddenRelay)
        .disposed(by: disposeBag)
}

问题是,测试变为红色,结果actualRetryCount为 6。删除share()函数返回相同的值(即重试 6 次)。所以,这意味着它像普通的 observable 一样被调用了两次,而不是共享的。为什么会这样?

现在,我所做的是将第二个继电器的发射放在一个.do(onNext:)块中,所以这不是真正的问题。我只是对这种行为感到困惑。

提前致谢。

标签: iosswiftrx-swift

解决方案


第一个调用creditCardInfoProvider()了 3 次,而第二个只调用了一次。

请记住,重试只会重新订阅,这将导致 Observable 再次执行其观察者闭包。在第一个函数中,重试是重新订阅just返回的 Observable,而第二个函数,重试是重新订阅error返回的 Observable。

如果你这样做了:

        let creditCardInfoProvider: CreditCardInfoProviderBlock = {
            return Observable.create { observer in
                actualRetryCount += 1
                observer.onError(RxCocoaURLError.unknown)
                return Disposables.create()
            }
        }

create然后每次进行新订阅时都会调用传递给的闭包,并且您会看到actualRetryCount预期的增量。


至于如何share工作......为了理解份额,您首先必须了解热与冷可观察对象。

一个热的 observable 与多个订阅者共享它的事件,而一个冷的 observable 则不。

例如:

let random = Observable<Int>.create { observer in
    observer.onNext(Int.random(in: 0..<1000))
    observer.onCompleted()
    return Disposables.create()
}

上面是一个冷的 observable(这是默认值)。这意味着每个订阅者都会收到一个不同的数字。如果这是一个网络呼叫,那么每个用户都会发起一个新的网络请求。

如果您希望多个订阅者获得相同的数据,则需要shareobservable...


推荐阅读