SwiftUI 和 Combine,如何创建可重用的发布者来检查字符串是否为空
SwiftUI and Combine, how to create a reusable publisher to check if a string is empty
我正在努力学习 SwiftUI 和 Combine 语法,并试图了解如何创建一个可重用的发布者来检查字符串是否为空。
我有一个 SwiftUI,它有 5 个文本字段,使用 @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/,并且我能够通过创建 [=13] 让我的 SwiftUI 正确地 enable/disable 我的计算按钮=] 和 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
或类似的东西,它采用字段绑定,如我的 $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 { ![=10=].isEmpty }
}
}
[=12=]
是闭包的第一个参数 shorthand,</code> 表示第二个,依此类推。</p>
<p><code>!
是Bool
反转运算符,前缀!
是shorthand后缀== 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
子句允许我们进一步限制这种一致性,表示我们只能在 Output
为 String
时对 Publisher
进行操作。 some Publisher
为我们提供了一个不透明的 return 类型,使我们不必编写已多次转换的 Publisher
的类型签名,您可以将其更改为 AnyPublisher<Bool, Never>
和如果愿意,可以使用 .eraseToAnyPublisher()
,但我建议仅在需要时使用该擦除。
我正在努力学习 SwiftUI 和 Combine 语法,并试图了解如何创建一个可重用的发布者来检查字符串是否为空。
我有一个 SwiftUI,它有 5 个文本字段,使用 @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/,并且我能够通过创建 [=13] 让我的 SwiftUI 正确地 enable/disable 我的计算按钮=] 和 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
或类似的东西,它采用字段绑定,如我的 $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 { ![=10=].isEmpty }
}
}
[=12=]
是闭包的第一个参数 shorthand,</code> 表示第二个,依此类推。</p>
<p><code>!
是Bool
反转运算符,前缀!
是shorthand后缀== 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
子句允许我们进一步限制这种一致性,表示我们只能在 Output
为 String
时对 Publisher
进行操作。 some Publisher
为我们提供了一个不透明的 return 类型,使我们不必编写已多次转换的 Publisher
的类型签名,您可以将其更改为 AnyPublisher<Bool, Never>
和如果愿意,可以使用 .eraseToAnyPublisher()
,但我建议仅在需要时使用该擦除。