SwiftUI 和 Combine,如何创建可重用的发布者来检查字符串是否为空

标签 swift swiftui combine

我正在尝试学习 SwiftUI 和 Combine 语法,并试图了解如何创建一个可重用的发布者来检查字符串是否为空。

我有一个带有 5 个 TextField 的 SwiftUI,它使用 @Binding 将它们连接到我的数据模型对象。

class DataWhatIsLoanPayment: ObservableObject {
    // Input
    @Published var pv = ""
    @Published var iyr = ""
    // a bunch more fields...

    // Output
    @Published var isvalidform = false
}

我想在填写完所有字段后启用“计算”​​按钮 (isEmpty == false)。

我正在关注 https://peterfriese.dev/swift-combine-love/ ,并且我能够通过创建一个 isValidPVPublisher 来让我的 SwiftUI 正确启用/禁用我的计算按钮。和一个 isValidIYRPublisher并将它们组合成 isValidFormPublisher ,像这样:

private var isValidPVPublisher: AnyPublisher<Bool, Never> {
    $pv
        .debounce(for: 0.8, scheduler: RunLoop.main)
        .removeDuplicates()
        .map { input in
            return input.isEmpty == false
        }
        .eraseToAnyPublisher()
}

private var isValidIYRPublisher: AnyPublisher<Bool, Never> {
    $iyr
        .debounce(for: 0.8, scheduler: RunLoop.main)
        .removeDuplicates()
        .map { input in
            return input.isEmpty == false
        }
        .eraseToAnyPublisher()
}


private var isValidFormPublisher: AnyPublisher<Bool, Never> {
    Publishers.CombineLatest(isValidPVPublisher, isValidIYRPublisher)
        .map { pvIsValid, iyrIsValid in
            return pvIsValid && iyrIsValid
        }
        .eraseToAnyPublisher()
}

init() {        
    isValidFormPublisher
        .receive(on: RunLoop.main)
        .assign(to: \.isValidForm, on: self)
        .store(in: &cancellableSet)
}

但是,我将拥有 2 个以上的字段,并且我将在我的应用程序中拥有许多其他表单,我将在其中检查我的字段是否为空。并重复 .debounce(for: 0.8, scheduler: RunLoop.main).removeDuplicates().map { input in return input.isEmpty == false }.eraseToAnyPublisher()一遍又一遍是个坏主意。

我想创建一个可重复使用的 NotEmptyPublisher ,或者类似的东西,它需要一个字段绑定(bind),比如我的 $pv并设置链,如 isValidPVPublisher 中所示以上。所以我可以有类似的东西:

// Something like this, but I'm not sure of the syntax...
private var isValidPVPublisher = NotEmptyPublisher(field:$pv)
// instead of ...
private var isValidPVPublisher: AnyPublisher<Bool, Never> {
    $pv
        .debounce(for: 0.8, scheduler: RunLoop.main)
        .removeDuplicates()
        .map { input in
            return input.isEmpty == false
        }
        .eraseToAnyPublisher()
}

但是我在解析很多我不熟悉的 Swift 语法时遇到了麻烦,而且我似乎无法弄清楚该怎么做,而且我在网上找到的每个示例都只是定义发布者内联链而不是可重复使用的方式。

如何创建可重复使用的发布器,这样我就不必重复这些做同样事情的内联发布器?

最佳答案

给你!

extension Publisher where Output == String {
    func isStringInhabited() -> Publishers.Map<Self, Bool> {
        map { !$0.isEmpty }
    }
}

$0是闭包第一个参数的简写,$1表示第二个,依此类推。

!Bool反转运算符,前缀 !是后缀 == false 的简写.

现在,关于您关于重用的问题,您不需要做那么困难的事情,您只需创建一个函数即可。

private func isValidTransform<P: Publisher>(input: P) -> some Publisher where P.Output == String {
    input
        .debounce(for: 0.8, scheduler: RunLoop.main)
        .removeDuplicates()
        .isStringInhabited()
}

P是泛型,这意味着它可以是任何类型,只要该类型符合 Publisher。 . where子句允许我们进一步限制这种一致性,表示我们只能对 Publisher 进行操作这是他们的 OutputString . some Publisher为我们提供了一个不透明的返回类型,使我们不必编写 Publisher 的类型签名多次变换后,可以改成AnyPublisher<Bool, Never>并使用 .eraseToAnyPublisher()如果你愿意,但我建议只在需要时使用该删除。

关于SwiftUI 和 Combine,如何创建可重用的发布者来检查字符串是否为空,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60983172/

相关文章:

ios - AVCaptureVideoPreviewLayer 看起来是 iPhone 4 大小

ios - SwiftUI - 如何关闭工作 TableView ,同时关闭该 View

swiftui - 在 ObservableObject 中引用 EnvironmentObject

SwiftUI 观察变化

ios - 快速加载 xib 文件的正确方法

swift - 屏幕无法缩放到正确的坐标 - swift google map api

swift - macOS 上的 NavigationLink 未在同一 View 中打开

swiftui - 如何在 SwiftUI 中传递进度值(也许使用组合)?

ios - SKView 到 UIView

swift - 在 SwiftUI 中动态隐藏 View