【问题标题】:Branching Combine operator, flatMap, and debounce oddity分支合并运算符、flatMap 和反跳怪
【发布时间】:2020-03-09 14:55:55
【问题描述】:

上下文

我正在遵循 WWDC 2019 722 https://developer.apple.com/videos/play/wwdc2019/722/ 和 WWDC 2019 721 https://developer.apple.com/videos/play/wwdc2019/721/ 的示例,并通过验证在字段上运行异步网络检查。

正如演讲中提到的,用户名字段应该:

  1. 去抖动
  2. 显示加载指示器
  3. 执行网络请求
  4. 以网络结果结束
  5. 隐藏加载指示器
  6. 并根据网络响应显示或隐藏验证消息

我有一个具有去抖动功能的原型,并使用延迟运算符模拟网络请求。大多数情况下,所有这些都运行良好。

let a = $firstName
    .debounce(for: .seconds(0.5), scheduler: DispatchQueue.main)
    .flatMap { name -> AnyPublisher<String, Never> in
        if name == "" {
            return Just(name)
                .eraseToAnyPublisher()
        } else {
            return Just(name)
                .handleEvents(receiveOutput: { _ in self.isFirstNameLoading = true})
                .delay(for: .seconds(2), scheduler: DispatchQueue.main)
                .handleEvents(receiveOutput: { _ in self.isFirstNameLoading = false})
                .eraseToAnyPublisher()
        }
    }
    .map { name -> Bool in name != "Q" }
    .assign(to: \.isFirstNameValid, on: self)

去抖会一直等到输入暂停。 flatMap 充当操作符组合流中的条件分支:如果值为空,则不理会网络请求;否则,如果去抖后该值有值,则执行网络请求。最后,我的例子是“Q”总是一个错误,用于模拟目的。

但是,小问题是去抖发生在分支之前。我想将 debounce 移到条件的 else 分支,就像这样。

let a = $firstName
    .flatMap { name -> AnyPublisher<String, Never> in
        if name == "" {
            return Just(name)
                .eraseToAnyPublisher()
        } else {
            return Just(name)
                .debounce(for: .seconds(0.5), scheduler: DispatchQueue.main)
                .handleEvents(receiveOutput: { _ in self.isFirstNameLoading = true})
                .delay(for: .seconds(2), scheduler: DispatchQueue.main)
                .handleEvents(receiveOutput: { _ in self.isFirstNameLoading = false})
                .eraseToAnyPublisher()
        }
    }
    .map { name -> Bool in name != "Q" }
    .assign(to: \.isFirstNameValid, on: self)

出现这种情况时,条件的真分支(空输入)运行正确,而flatMap之后的map+assign运行正确。但是,当输入有值并且条件的 else 分支运行时,去抖动之后什么都不会运行。

我尝试将DispatchQueue 切换为OperationQueue.mainRunLoop.main 无济于事。

在条件工作之前保持去抖动现在可以,但我想知道我是否在尝试将其放入分支时做错了什么。我还想知道这是否是使用 Combine 在运算符中进行“分支”的正确方法,尤其是在我使用 flatMapJust() 时。

任何帮助将不胜感激!

【问题讨论】:

    标签: swift combine


    【解决方案1】:

    Just 只产生一个输出。将debounce 附加到它不会去抖动任何东西。充其量,它只会将Just 的输出延迟去抖动间隔。在最坏的情况下,有一个错误使它无法正常工作,这就是根据您的描述听起来的样子。

    【讨论】:

    • 我想知道是不是因为Just 发布者在去抖动期结束之前“完成”了。来自关于 Just 的文档:“发布者只向每个订阅者发出一次输出,然后完成。”
    • 我在示例中选择使用节流阀,但您所追求的几乎完全是使用组合的示例代码 - 参考:heckj.github.io/swiftui-notes/…heckj.github.io/swiftui-notes/…
    猜你喜欢
    • 2020-05-09
    • 1970-01-01
    • 2011-03-16
    • 2020-11-05
    • 2020-01-10
    • 2011-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多