2017-11-06 16 views
0

私はrxSwiftを使い慣れました。私は3つの観測値、checkAccount、fetchMails、fetchFoldersを持っています。
fetchMailsとfetchFoldersはcheckAccountの結果に依存します。 UIButton Tapを使用してfetchMailsおよびfetchFolders操作を呼び出すにはどうすればよいですか?また、checkAccountの成功が成功した場合は、fetchMailsとfetchFoldersを実行するたびに実行するものはありません。 checkAccountが失敗した場合は、fetchMailsとfetchFoldersを実行したときにcheckAccountを再試行します。どうすればこの目的を達成できますか?そしてこれは私のコードです:rxSwift観測可能な依存関係

@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の回答によると、私はこのようなbutton.rx.tapからflatmapする観測可能fetchFodersとfetchMailsを変更するが、それでも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演算子を使用できます。 flatMapretryWhencheckAccountのエラーストリームで、checkAccountが成功すると操作は再試行されます。

ボタンからストリームを開始するには、button.rx.tapflatMapです。例えば

あなたはbutton.rx.tapcheckAcount()からfetchMail()する場合は複数回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. 
     } 
    } 
} 
+0

おかげで非常に。私はbutton.rx.tapを使ってfetchMailsとfetchfoldersを現在どのように呼び出すかを理解しています。しかし、私はちょうど私の目的を達成するためにcheckAccountを作るためにretrywhenを使う方法を知らない:checkAccount成功、それは一度だけ動く。 checkaccountが失敗した場合、fetchmailsは常に成功するまでcheckaccountを試みます。私にいくつかのコードを教えてもらえますか? –

+0

@ bupo.jung私の更新された答えの例を見てください。あなたの問題を解決しますか? –

+0

いいえ、私が欲しいものではありません。私はfetchmailsがcheckaccountの結果に依存していることを意味します。最初にボタンcheckaccountの成功をタップし、fetchmailsを実行して結果を取得したら、その後に他のタップがfetchmailsのみを実行します。ボタンcheckaccountの最初のタップが失敗した場合、私はfetchmailsを実行しませんがエラーを表示してから、もう一度タップボタンを押してください。 –

関連する問題