防反跳操作符会中断Combine中的发布者

时间:2019-10-03 08:06:34

标签: swift reactive-programming combine

嗨,我有以下数据模型用于在我的应用中注册用户:

import Foundation
import Combine
import SwiftExtensions

class RegisterData {

    @Published var firstName: String = ""
    @Published var middleName: String = ""
    @Published var lastName: String = ""
    @Published var email: String = ""
    @Published var postcode: String = ""
    @Published var termsAggreed: Bool = false
    @Published var receiveNews: Bool = false
}

extension RegisterData: Publisher {

    typealias Output = Bool

    typealias Failure = Never

    func receive<S>(subscriber: S) where S : Subscriber, RegisterData.Failure == S.Failure, RegisterData.Output == S.Input {

        // works only if debounce transform is removed or moved after all combineLatest transforms
        let publisher = $firstName
            .combineLatest($middleName, $lastName) { !$0.isEmpty && !$1.isEmpty && !$2.isEmpty }
            .combineLatest($postcode, $email) { $0 && !$1.isEmpty && $2.isValidEmail }
            .debounce(for: .seconds(0.5), scheduler: RunLoop.main) // try to debounce only texts, but not working
            .combineLatest($receiveNews, $termsAggreed) { $0 && $1 && $2 }
            .removeDuplicates()
            .eraseToAnyPublisher()

        publisher.receive(subscriber: subscriber)
    }
}

我有一个视图控制器,其中有两个UITextField和两个UISwitch,它们填充了RegisterData类的一个实例

我只想“反跳”存储字符串的属性的更改,因为用户将在文本字段中填充它们,但是我在func receive<S>(subscriber:)中应用这些转换的方式是我需要的Publisher使其不发送任何新值。如果我注释掉.debounce转换,它将发送更新。如果我将.debounce转换放在.removeDuplicates()之前,它将发送更新,但是也会“反跳”布尔值。

如何仅对String进行去抖动?

我尝试逐个反跳其中的每一个(让我们说其中一个拥有潜在的用户名,如果用户名是免费的,则必须在服务器上进行检查,因此我只想对它的API调用进行反跳),但并没有工作

谢谢!

1 个答案:

答案 0 :(得分:0)

这个问题已经很老了,但是如果到目前为止您还没有找到解决方案,那么也许您正在寻找以下内容:

您的带有$前缀的字符串本身就是发布者,因此您可以通过在每个字符串上应用反跳操作符来简单地对其进行“反跳”。

您的代码如下所示:

let publisher = $firstName.debounce(for: .seconds(0.5), scheduler: RunLoop.main)
    .combineLatest(
        $middleName
            .debounce(for: .seconds(0.5), scheduler: RunLoop.main),
        $lastName
            .debounce(for: .seconds(0.5), scheduler: RunLoop.main)) {
                !$0.isEmpty && !$1.isEmpty && !$2.isEmpty
    }
    .combineLatest(
        $postcode
            .debounce(for: .seconds(0.5), scheduler: RunLoop.main),
        $email
            .debounce(for: .seconds(0.5), scheduler: RunLoop.main)) {
                $0 && !$1.isEmpty && !$2.isEmpty
    }
    .combineLatest($receiveNews, $termsAggreed) { $0 && $1 && $2 }
    .removeDuplicates()
    .eraseToAnyPublisher()

代码重复很丑陋,但也许您可以对此进行扩展。