swift - SwiftUI和Combine,如何创建一个可重用的发布者来检查一个字符串是否为空
问题描述
我正在努力学习 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/,我能够让我的 SwiftUI 通过创建一个isValidPVPublisher
和一个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 { !$0.isEmpty }
}
}
$0
是闭包的第一个参数的简写,$1
表示第二个参数,依此类推。
!
是Bool
反转运算符,prefixing!
是 suffixing 的简写== 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
时对 s 进行操作。为我们提供了一个不透明的返回类型,以使我们不必编写已多次转换的 a 的类型签名,您可以将其更改为并根据需要使用,但我建议仅在需要时使用该擦除。Output
String
some Publisher
Publisher
AnyPublisher<Bool, Never>
.eraseToAnyPublisher()
推荐阅读
- powershell - 如何递归搜索特定文件,创建文件夹并将文件移动到其中?
- typescript - 角度拖放事件不起作用 `drop` 事件未触发
- c++ - C++ LDAP检查用户是否是特定组的成员
- c# - 将.net core 应用程序发布到 iis 后操作超时?
- javascript - 如何使用 Node.JS 编辑当前以上的控制台行?
- java - GSON 序列化因自定义对象而失败
- .net - Ef Core 3.1 值转换器
- node.js - 在构建 React.js 上设置环境变量
- dialogflow-es - 无法让丰富的按钮在对话流上工作。它返回空响应
- reactjs - 如何在useEffect-React加载的组件中渲染内容