SwiftUI和合并,如何创建可重用的发布器以检查字符串是否为空

tyg4sfes  于 2022-11-28  发布在  Swift
关注(0)|答案(1)|浏览(105)

我正在尝试学习SwiftUI和合并语法,并尝试了解如何创建一个可重用的发布器,该发布器将检查字符串是否为空。
我有一个带有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和一个isValidIYRPublisher并将它们组合成一个isValidFormPublisher,我能够让我的SwiftUI正确地启用/禁用我的Calculate按钮,如下所示:

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,或者类似的东西,它接受一个字段绑定,就像我的$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语法时遇到了麻烦,我似乎不知道如何做到这一点,我在网上找到的每个例子都只是内联地定义发布者链,而不是以一种可重用的方式。
如何创建一个可重用的发布器,以便不必重复这些内联发布器(它们都做同样的事情)?

ldioqlga

ldioqlga1#

你在这里!

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是一个泛型,这意味着它可以是任何类型,只要该类型符合Publisherwhere子句允许我们进一步约束这种一致性,表示当OutputString时,我们只能对Publisher进行操作。some Publisher保存我们提供了一个不透明的返回类型,如果愿意,可以将其更改为AnyPublisher<Bool, Never>并使用.eraseToAnyPublisher(),但我建议只在需要时使用擦除。

相关问题