2016-05-26 2 views
6

Я изучаю пример кода в RxSwift. В файле GithubSignupViewModel1.swift, определение validatedUsername является:Путаница о flatMapLatest в RxSwift

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: показано , но показал только одно сообщение --------> 3:.

Когда я вводим символы медленнее, сообщение --------> 1 :, --------> 2 :, --------> 3: показано последовательно.

Но когда я изменяю flatMapLatest на flatMap, сколько символов я ввожу, я получу то же количество сообщений --------> 3:.

А как работает flatMapLatest?

Как flatMapLatest фильтрует ранний отклик от NSURLResponse?

Я читал некоторые о flatMapLatest, но никто из них не объяснит мое замешательство.

То, что я увидел что-то вроде:

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

a.value При изменении в другой переменной, то переменная (XX) не будет влиять на абоненту.

Но input.username не изменяется, это всегда testfield.rx_text! Итак, как работает flatMapLatest?

ответ

8

Неясно, о чем ваше замешательство. Вы спрашиваете разницу между flatMap и flatMapLatest? flatMap будет отображаться на новом Observable, и если понадобится снова flatMap, он по существу объединит два отображаемых Observable s в один. Если нужно снова flatMap, он будет объединить его снова и т.д.

С flatMapLatest, когда новый Observable отображается, он переписывает последний Observable если был один. Слияния нет.

EDIT: В ответ на ваш комментарий, причина вы не видите никакого "------>3:" печати, потому что эти rx_requestObservable s выбыли прежде, чем они могли бы конкурировать, потому что flatMapLatest получил новый элемент, и это отображается на новый Observable , После удаления rx_request, вероятно, отменяет запрос и не будет запускать обратный вызов там, где вы печатаете. Старое Observable расположено, потому что оно больше не принадлежит никому, когда новый занимает его место.

+0

'input.name' не изменен! Есть только один «Наблюдаемый». Закрытие в flatMapLatest вызывалось каждый раз, но сетевой запрос возвращался только один раз. – leizh00701

+0

Проверьте изменения. – solidcell

+2

У меня появилось другое объяснение о 'flatMapLatest', и это решило мое замешательство. https://github.com/baconjs/bacon.js/wiki/Diagrams. Спасибо. – leizh00701

9

ответ TheDroidsOnDroid ясна для меня:

FlatMapLatest diagram

Ну, flatMap() получает одно значение, а затем выполняет длинные задачи, и когда он получает следующее значение, предыдущее задание будет еще закончить даже когда новое значение приходит в середину текущей задачи. Это не совсем то, что нужно , потому что, когда мы получим новый текст в строке поиска, мы хотим, чтобы отменил предыдущий запрос и запустил другой. Это то, что flatMapLatest() делает.

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

Вы можете использовать RxMarbles приложение на Appstore играть с операторами.

4

Я считаю это https://github.com/ReactiveX/RxSwift/blob/master/Rx.playground/Pages/Transforming_Operators.xcplaygroundpage/Contents.swift быть полезным

Трансформирует элементы, излучаемые наблюдаемым последовательности в Наблюдаемые последовательности, и сливается выбросы из обоего Наблюдаемых последовательностей в одну последовательность наблюдаемой. Это также полезно, например, когда у вас есть наблюдаемая последовательность, которая сама генерирует наблюдаемые последовательности, и вы хотите иметь возможность реагировать на новые выбросы из наблюдаемой последовательности. Разница между 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 начнет излучать элементов, но предыдущая внутренняя наблюдаемая последовательность (.score) будет также все еще излучать элементы. Изменив flatMap на flatMapLatest, только самая последняя внутренняя наблюдаемая последовательность (.score) будет излучать элементов, то есть значение .score.value до 95 не влияет.

flatMapLatest - это на самом деле комбинация карты и switchLatest операторов.

Кроме того, я считаю, https://www.raywenderlich.com/158205/rxswift-transforming-operators это будет полезно

flatMap

следит за каждым наблюдаемым он создает, один для каждого элемента добавляется на источник наблюдаемого

flatMapLatest

Что отличает flatMapLatest от другого, так это то, что он автоматически переключится на последнюю наблюдаемую и отмену подписки на предыдущую.