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はどのように機能するのでしょうか。
あなたの混乱が何であるかは明らかではありません。 flatMap
とflatMapLatest
の違いに疑問がありますか? flatMap
は新しいObservable
にマップされ、再度flatMap
が必要な場合は、2つのマップされたObservable
sを1つに本質的にマージします。再度flatMap
が必要な場合は、再度マージします。
flatMapLatest
を使用すると、新しいObservable
がマップされると、最後のObservable
が存在する場合は上書きされます。マージはありません。
編集:コメントへの回答として、何も表示されない理由"------>3:"
印刷はrx_request
Observable
は新しい要素を受け取り、これが新しいflatMapLatest
にマッピングされたため、競合する前に破棄されました。処分すると、rx_request
おそらくリクエストをキャンセルし、印刷中のコールバックを実行しません。古いObservable
は破棄されます。これは、新しいObservable
が代わったときに誰にも属していないためです。
TheDroidsOnDroidの答えは私には明らかです:
まあ、flatMap()は1つの値を取得してから長いタスクを実行し、次の値を取得すると、現在のタスクの途中で新しい値が到着しても、前のタスクは終了します。検索バーに新しいテキストが表示されたら、前のリクエストをキャンセルして別のリクエストを開始したいため、実際には必要ありません。それがflatMapLatest()が行うことです。
http://www.thedroidsonroids.com/blog/ios/rxswift-examples-3-networking/
AppstoreのRxMarblesアプリを使用して、オペレーターと遊ぶことができます。
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の違いは、最新のオブザーバブルに自動的に切り替わり、以前のオブザーバブルからサブスクライブを解除することです。
Ray Wenderlichチュートリアル のこの図が役立つと思います。