SwiftUI 结合 ViewModel 电子邮件验证

Posted

技术标签:

【中文标题】SwiftUI 结合 ViewModel 电子邮件验证【英文标题】:SwiftUI Combine ViewModel Email Validation 【发布时间】:2021-10-07 08:17:57 【问题描述】:

如何使用 combine 验证结合这两个代码的视图模型中的电子邮件?

这是在我的 RegisterViewModel 中

private var isEmailValidPublisher: ValidatePublisher 
        $email
            .removeDuplicates()
            .map  $0.trimmingCharacters(in: .whitespacesAndNewlines).count >= 10
            .handleEvents(receiveOutput:  [weak self] in $0 ? (self?.emailMessage = "") : (self?.emailMessage = "Invalid email"))
            .eraseToAnyPublisher()
    

我想在 isEmailValidPublisher 中添加此验证。

func isValidEmail() -> Bool 
        let emailRegEx = "(?:[\\pL0-9!#$%\\&'*+/=?\\^_`|~-]+(?:\\.[\\pL0-9!#$%\\&'*+/=?\\^_`|" + "~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\" + "x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[\\pL0-9](?:[a-" + "z0-9-]*[\\pL0-9])?\\.)+[\\pL0-9](?:[\\pL0-9-]*[\\pL0-9])?|\\[(?:(?:25[0-5" + "]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.)3(?:25[0-5]|2[0-4][0-9]|[01]?[0-" + "9][0-9]?|[\\pL0-9-]*[\\pL0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21" + "-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])"
        
        let emailValidation = NSPredicate(format:"SELF MATCHES[c] %@", emailRegEx)
        return emailValidation.evaluate(with: self)
    

如何在 isEmailValidPublisher 中混合它们,以便我可以在我的注册视图中使用该信息,如下所示

 Image(systemName: "envelope")
                    .foregroundColor(registerVM.emailMessage != "" ? .red: .blue)

【问题讨论】:

我假设isValidEmail() 是String 类的扩展? 确实如此。 @丹尼尔T。有什么改变吗? 【参考方案1】:

假设你有一个像这样的简单视图:

struct ContentView: View 
    
    @StateObject var controller = Controller()
    
    var body: some View 
        VStack 
            TextField("email", text: $controller.email)
                .foregroundColor(controller.inputValid ? .primary : .red)
            controller.validationMessage.map  message in
                Text(message)
                    .foregroundColor(.red)
            
        
    

并且您希望在 ObservableObject 中包含逻辑:

class Controller: ObservableObject 
    
    @Published var email = ""
    @Published private(set) var validationMessage: String?
    
    var inputValid: Bool 
        validationMessage == nil
    
    
    
    init() 
        // you subscribe to any changes to the email field input
        $email
        // you ignore the first empty value that it gets initialised with
            .dropFirst()
        // you give the user a bit of time to finish typing
            .debounce(for: 0.6, scheduler: RunLoop.main)
        // you get rid of duplicated inputs as they do not change anything in terms of validation
            .removeDuplicates()
        // you validate the input string and in case of problems publish an error message 
            .map  input in
                guard !input.isEmpty else 
                    return "Email cannot be left empty"
                
                guard input.isValidEmail() else 
                    return "Email is not valid"
                
        // in case the input is valid the error message is nil
                return nil
            
        // you publish the error message for the view to react to
            .assign(to: &$validationMessage)
    

【讨论】:

以上是关于SwiftUI 结合 ViewModel 电子邮件验证的主要内容,如果未能解决你的问题,请参考以下文章

从 ViewModel 弹出导航视图

SwiftUI - MVVM之ViewModel

SwiftUI:从 ViewModel 更改视图 @State 属性

如何在 SwiftUI 中通过 ViewModel 传播模型更改?

SwiftUI 中 ViewModel + View 之间的通信

基于 VIewModel 状态更新 SwiftUI 视图?