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.
}
}
}