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



我正在努力学习SwiftUI和Combine语法,并试图了解如何创建一个可重复使用的发布服务器,以检查String是否为空。

我有一个SwiftUI,它有5个TextFields,使用@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/,并且我能够通过创建isValidPVPublisherisValidIYRPublisher并将它们组合到isValidFormPublisher中来使我的SwiftUI正确地启用/禁用我的计算按钮,如下所示:

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语法时遇到了困难,而且我似乎不知道如何做到这一点,而且我在网上找到的每个例子都只是内联定义发布链,而不是以可重复使用的方式。

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

给你!

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为我们提供了一个不透明的返回类型,使我们不必编写经过多次转换的Publisher的类型签名,如果您愿意,您可以将其更改为AnyPublisher<Bool, Never>并使用.eraseToAnyPublisher(),但我建议仅在需要时使用该擦除。

相关内容

最新更新