web-dev-qa-db-ja.com

RxSwiftのflatMapLatestに関する混乱

RxSwiftでサンプルコードを学びました。 GithubSignupViewModel1.Swiftファイルで、validatedUsernameの定義は次のとおりです。

validatedUsername = input.username //the username is a textfiled.rx_text
    .flatMapLatest { username -> Observable<ValidationResult> in
        print("-------->1:")
        return validationService.validateUsername(username)
            .observeOn(MainScheduler.instance)
            .catchErrorJustReturn(.Failed(message: "Error contacting server"))
    }
    .shareReplay(1)

validateUsernameメソッドは、最終的に次のメソッドと呼ばれます。

func usernameAvailable(username: String) -> Observable<Bool> {
    // this is ofc just mock, but good enough
    print("-------->2:")
    let URL = NSURL(string: "https://github.com/\(username.URLEscaped)")!
    let request = NSURLRequest(URL: URL)
    return self.URLSession.rx_response(request)
        .map { (maybeData, response) in
            print("-------->3:")
            return response.statusCode == 404
        }
        .catchErrorJustReturn(false)
}

ここに私の混乱があります:

ユーザー名のテキストフィールドにすばやく文字を入力するたびに、メッセージ--------> 1:、--------> 2:が表示され、少し後のメッセージ-------- > 3:表示されましたが、1つだけ表示されました--------> 3:メッセージ。

文字入力が遅いと、メッセージ--------> 1:、--------> 2:、--------> 3:が連続して表示されます。

しかし、flatMapLatestをflatMapに変更すると、入力した文字数は同じ数の--------> 3:メッセージになります。

では、ここでflatMapLatestはどのように機能しましたか?

FlatMapLatestはNSURLResponseからの初期応答をどのようにフィルタリングしますか?


私はflatMapLatestについていくつか読んだが、どれも私の混乱を説明するものではない。

私が見たものは次のようなものです:

let a = Variable(XX)
a.asObservable().flatMapLatest(...)

変更時a.valueを別の変数に追加すると、Variable(XX)はaのサブスクライバーに影響を与えません。

しかし input.usernameは変更されず、常にtestfield.rx_text!では、flatMapLatestはどのように機能するのでしょうか。

13
leizh00701

あなたの混乱が何であるかは明らかではありません。 flatMapflatMapLatestの違いに疑問がありますか? flatMapは新しいObservableにマップされ、再度flatMapが必要な場合は、2つのマップされたObservablesを1つに本質的にマージします。再度flatMapが必要な場合は、再度マージします。

flatMapLatestを使用すると、新しいObservableがマップされると、最後のObservableが存在する場合は上書きされます。マージはありません。

編集:コメントへの回答として、何も表示されない理由"------>3:"印刷はrx_requestObservableは新しい要素を受け取り、これが新しいflatMapLatestにマッピングされたため、競合する前に破棄されました。処分すると、rx_requestおそらくリクエストをキャンセルし、印刷中のコールバックを実行しません。古いObservableは破棄されます。これは、新しいObservableが代わったときに誰にも属していないためです。

14
solidcell

TheDroidsOnDroidの答えは私には明らかです:

FlatMapLatestダイアグラム

まあ、flatMap()は1つの値を取得してから長いタスクを実行し、次の値を取得すると、現在のタスクの途中で新しい値が到着しても、前のタスクは終了します。検索バーに新しいテキストが表示されたら、前のリクエストをキャンセルして別のリクエストを開始したいため、実際には必要ありません。それがflatMapLatest()が行うことです。

http://www.thedroidsonroids.com/blog/ios/rxswift-examples-3-networking/

AppstoreのRxMarblesアプリを使用して、オペレーターと遊ぶことができます。

16
dangthaison.91

これは https://github.com/ReactiveX/RxSwift/blob/master/Rx.playground/Pages/Transforming_Operators.xcplaygroundpage/Contents.Swift 役立つと思います

Observableシーケンスによって放出された要素をObservableシーケンスに変換し、両方のObservableシーケンスからの放出を単一のObservableシーケンスにマージします。 これは、たとえば、それ自体がObservableシーケンスを放出するObservableシーケンスがあり、どちらかのObservableシーケンスからの新しい放出に反応できるようにしたい場合にも役立ちます。 flatMapとflatMapLatestの違いは、flatMapLatestは最新の内部のObservableシーケンスからのみ要素を発行することです。

    let disposeBag = DisposeBag()

    struct Player {
        var score: Variable<Int>
    }

    let ???????? = Player(score: Variable(80))
    let ???????? = Player(score: Variable(90))

    let player = Variable(????????)

    player.asObservable()
        .flatMap { $0.score.asObservable() } // Change flatMap to flatMapLatest and observe change in printed output
        .subscribe(onNext: { print($0) })
        .disposed(by: disposeBag)

    ????????.score.value = 85

    player.value = ????????

    ????????.score.value = 95 // Will be printed when using flatMap, but will not be printed when using flatMapLatest

    ????????.score.value = 100

flatMapを使用すると、

80
85
90
95
100

flatMapLatestを使用すると、

80
85
90
100

この例では、flatMapを使用すると予期しない結果が生じる可能性があります。 ????????を割り当てた後player.valueに、????????。scoreは要素を放出し始めますが、以前の内側のObservableシーケンス(????????。score)も要素を放出します。 flatMapをflatMapLatestに変更すると、最新の内部のObservableシーケンス(????????。score)のみが要素を放出します。つまり、????????。score.valueを95に設定しても効果はありません。

flatMapLatestは、実際にはmapオペレーターとswitchLatestオペレーターの組み合わせです。

また、私は https://www.raywenderlich.com/158205/rxswift-transforming-operators これが便利だと思います

flatMap

それが作成するすべてのオブザーバブルに対応し、ソースオブザーバブルに追加された要素ごとに1つ

flatMapLatest

FlatMapLatestの違いは、最新のオブザーバブルに自動的に切り替わり、以前のオブザーバブルからサブスクライブを解除することです。

9
onmyway133

Ray Wenderlichチュートリアル のこの図が役立つと思います。

flatMapLatest diagram

4
Nominalista