我在swiftUI中有一个用户名textField。我正试图在出版商的帮助下验证输入。
这是我的代码:
View
struct UserView: View {
@StateObject private var userViewModel = UserViewModel()
init(){
UITextField.appearance().semanticContentAttribute = .forceRightToLeft
UITextField.appearance().keyboardAppearance = .dark
}
var body: some View {
SecureField("", text: $userViewModel.passwordText)
Text(userViewModel.passwordError).foregroundColor(.red)
.frame(width: 264, alignment: .trailing)
}
}
视图模型
ViewModel
final class UserViewModel: ObservableObject {
private var cancellables = Set<AnyCancellable>()
@Published var userText: String = ""
@Published var userTextError = ""
private var usernamevalidation: AnyPublisher<(username:String, isValid: Bool), Never> {
return $userText
.dropFirst()
.map{(username:$0, isValid: !$0.isEmpty)}
.eraseToAnyPublisher()
}
private var usernamevalidated: AnyPublisher<Bool,Never> {
return usernamevalidation
.filter{$0.isValid}
.map{$0.username.isValidUserName()}
.eraseToAnyPublisher()
}
init(){
usernamevalidation.receive(on: RunLoop.main)
.map{$0.isValid ? "": "Emptyusername "}
.assign(to: .userTextError, on: self)
.store(in: &cancellables)
usernamevalidated.receive(on: RunLoop.main)
.map{$0 ? "" : "wrong username "}
.assign(to: .userTextError, on: self)
.store(in: &cancellables)
}
}
扩展
extension String {
func isValidUserName() -> Bool {
let usernameRegex = "^[a-zA-Z0-9_-]*$"
let usernamepred = NSPredicate(format:"SELF MATCHES %@", usernameRegex)
return usernamepred.evaluate(with: self)
}
}
在ViewModel的init((块中验证的用户名中,我将错误分配给userTextError属性,该属性应反映在文本视图中。如果出现特殊字符,如@或%。。等等。发生的情况是,有时错误显示为红色,而其他错误显示为否,即使我试图在映射运算符之后打印字符串的值,我也可以在打印中看到字符串。只是错误有时会反映在视图中,有时不会。我是不是错过了什么或做了一些根本错误的事情
问题是usernamevalidation
和usernamevalidated
都是计算属性。存储它们可以解决问题,但您也可以通过观察对userText
的更改、验证它们并分配给userTextError
来简化视图模型,如下所示:
final class UserViewModel: ObservableObject {
@Published var userText: String = ""
@Published private(set) var userTextError = ""
init() {
$userText
.dropFirst()
.map { username in
guard !username.isEmpty else {
return "Username is empty"
}
guard username.isValidUserName() else {
return "Username is invalid"
}
return ""
}
.receive(on: RunLoop.main)
.assign(to: &$userTextError)
}
}
还值得一提的是,用.assign(to: &$userTextError)
替换.assign(to: .userTextError, on: self)
可以消除内存泄漏,这意味着您确实需要将其存储在cancellables
中。
不要为发布者使用可计算的存储属性(以保持它们的活力(,如
private lazy var usernamevalidation: AnyPublisher<(username:String, isValid: Bool), Never> = {
return $userText
.dropFirst()
.map{(username:$0, isValid: !$0.isEmpty)}
.eraseToAnyPublisher()
}()
上一个答案(如果需要,请参阅编辑(是不正确的,因为Emptyusername
错误将被覆盖,这不是我们需要的(我的错误(。
事实证明,问题是iOS 14更新了用户界面!这个修复程序,我以前不得不在TextField
上使用过,看起来有点不寻常,但它确实起到了作用。
只需在视图主体中添加以下内容:
var body: some View {
let _ = userViewModel.userTextError
/* Rest of view as before */
}