rxSwift Наблюдаемая зависимость

Я новичок в rxSwift. У меня есть 3 наблюдаемые, checkAccount, fetchMails и fetchFolders.
fetchMails и fetchFolders зависят от результата checkAccount. Как я могу вызвать операцию fetchMails и fetchFolders с помощью UIButton Tap? И если проверка checkAccount будет успешной, я не буду запускать ее каждый раз, когда получаю fetchMails и fetchFolders. Если checkAccount не удалось, я хочу повторить checkAccount при fetchMails и fetchFolders. Как я могу достичь этой цели? и это мой код:

@IBOutlet weak var btn1: UIButton!
@IBOutlet weak var btn2: UIButton!
var checkAccountO: Observable<Bool>?
let bag = DisposeBag()

let fetchO: Observable<[String]> = Observable.create { observer in
        DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(1000)) {
            observer.onNext(["1","2"])
        }
        return Disposables.create()
    }

let fetchFolderO: Observable<[String]>  =  Observable.create { observer in
        DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(1000)) {
            observer.onNext(["folder1","folder2"])
        }
        return Disposables.create()
    }
override func viewDidLoad() {
    super.viewDidLoad()

    fetchFolders().subscribe { (evetn) in
        print("folders \(evetn)")
    }.addDisposableTo(bag)

    fetchMails().subscribe { (evetn) in
        print("mails \(evetn)")
    }.addDisposableTo(bag)
}

func checkAccount() -> Observable<Bool> {
    if let ob = checkAccountO {
        return ob
    }
    checkAccountO = Observable.create { (observer) -> Disposable in
        print("checking...")
        DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(1000)) {
            let i = arc4random() % 2
            if i == 0 {
                print("succ")
                observer.onNext(true)
                observer.onCompleted()
            }else {
                print("failed:\(i)")
                let err = NSError.init(domain: "err", code: 1001, userInfo: nil)
                observer.onError(err)
            }
        }
        return Disposables.create()
    }.retry(3).shareReplay(1)
    return checkAccountO!
}

func fetchMails() -> Observable<[String]> {
    return checkAccount().flatMap({ (_) -> Observable<[String]> in
        return self.fetchO
    })
}

func fetchFolders() -> Observable<[String]> {
    return checkAccount().flatMap({ (_) -> Observable<[String]> in
        return self.fetchFolderO
    })
}

согласно ответу @Timofey Solonin, я изменяю fetchFoders и fetchMails, наблюдаемые на flatmap, из button.rx.tap, как это, но все еще не знаю, как использовать retrywhen

    func fetchMails() -> Observable<[String]> {
    let rxtap = btn1.rx.tap
    return rxtap.flatMap { (_) -> Observable<[String]> in
        return self.checkAccount().flatMap({ (_) -> Observable<[String]> in
            return self.fetchO
        })
    }

}

func fetchFolders() -> Observable<[String]> {
    let rxtap = btn2.rx.tap
    return rxtap.flatMap { (_) -> Observable<[String]> in
        return self.checkAccount().flatMap({ (_) -> Observable<[String]> in
            return self.fetchFolderO
        })
    }
}

1 ответ

Ты можешь использовать retryWhen оператор. flatMap поток ошибок от retryWhen в checkAccount и если checkAccount будет успешным, ваша операция будет повторена.

Для запуска потока с кнопки вы используете button.rx.tap а также flatMap Это.

Например, если вы хотите fetchMail() от button.rx.tap а также checkAcount() несколько раз, если fetchMail() по ошибке вы можете использовать:

btn1.rx.tap.flatMapLatest {
    fetchMails().retryWhen{ errors in 
        errors.flatMapLatest{ _ in 
            checkAccount().retry() //or you can use retry(n) if you want to retry checkAccount limited amount of times.
            //fetchMails() will repeat if checkAccount() will return anything. Just keep in mind that retryWhen block is not going to be called if checkAccount() was successful.
        }
    }
}
Другие вопросы по тегам