RxSwift:立即交付第一个项目,然后反跳以下项目

时间:2018-07-15 00:05:30

标签: ios swift rx-swift rx-cocoa

我有一个要验证的文本字段,我想在用户键入时禁用按钮。用户停止键入(在1秒钟后反跳)后,将执行验证,并根据结果有条件地启用按钮。请注意,当用户只键入一个字符时,仍然会发生验证。

--"a"-"ab"-"abc"------------------"ab"--"a"------------------"ab"-----------------

--false---------validate("abc")---false----validate("a")-----false--validate("ab")

此SO(Deliver the first item immediately, 'debounce' following items)在RxJava中提出了以下解决方案。但这似乎只返回第一个元素,而不是在用户反跳后再次开始输入时不返回?如果我错了请纠正我

Observable.from(items).publish(publishedItems -> 
    publishedItems.limit(1).concatWith(
        publishedItems.skip(1).debounce(1, TimeUnit.SECONDS)
    )
)

2 个答案:

答案 0 :(得分:1)

一种选择是将问题“用户正在输入”与“输入是否有效”分开。

一种描述用户是否在打字的笨拙方式:

let isTyping = PublishSubject<Bool>()

textField.rx.text
    .map { _ in true }
    .bind(to: isTyping)
    .disposed(by: disposeBag)

textField.rx.text
    .debounce(1.0, scheduler: MainScheduler.instance)
    .map { _ in false}
    .bind(to: isTyping)
    .disposed(by: disposeBag)

然后,您可以这样描述按钮启用状态:

isTyping.withLatestFrom(isValid) { !$0 && $1 }
            .bind(to: button.rx.isEnabled)

当然,要使该方法在用户开始键入后立即生效,最好isValid以一个值开头。

您还可以按照以下方式简化此操作。如果这些值仅在本地使用,则可以。

textField.rx.text
    .map { _ in false }
    .bind(to: button.rx.isEnabled)
    .disposed(by: disposeBag)

textField.rx.text
    .debounce(1.0, scheduler: MainScheduler.instance)
    .flatMap { [weak self] in self?.validate($0) }
    .bind(to: button.rx.isEnabled)
    .disposed(by: disposeBag)

请注意,使用这种方法,当用户恢复输入时,将需要取消异步验证操作。

希望有人可以提出更清洁的解决方案,但是我认为这是一个不错的起点。

答案 1 :(得分:0)

经过深思熟虑,我可以通过以下方式完全解决问题,一切都按我的预期进行

    let input = textField.rx.text.distinctUntilChanged()
    let keystroke = input.map { _ in Observable.just(false) }
    let validate = input
        .flatMap { Observable.from(optional: $0) }  // 1  
        .filter { $0.count >= minimumTextLength }      
        .debounce(1, scheduler: MainScheduler.instance)
        .map { self.networkManager.validate($0).asObservable() } // 2
    return Observable.merge(keystroke, validate).switchLatest().distinctUntilChanged() // 3
  1. 安全解开可选字符串
  2. 在我的情况下,
  3. validate返回Single<Bool>,所以我将其转换为Observable。请注意,我故意使用map而不是flatMap来使用步骤3中的switchLatest提供的功能
  4. 我将a和b合并以创建Observable<Observable<Bool>>switchLatest允许我忽略validate的结果(如果用户再次开始输入)。 distinctUntilChanged丢弃重复的false s