SwiftUI Combine框架下ViewModel中合并实现邮箱校验的方法
实现方案
步骤1:将邮箱正则校验封装为String扩展
你原来的isValidEmail方法本质是String的校验工具,先把它封装成String的扩展方便全局调用:
extension String { func isValidEmail() -> Bool { let emailRegEx = "(?:[\\p{L}0-9!#$%\\&'*+/=?\\^_`{|}~-]+(?:\\.[\\p{L}0-9!#$%\\&'*+/=?\\^_`{|}" + "~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\" + "x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[\\p{L}0-9](?:[a-" + "z0-9-]*[\\p{L}0-9])?\\.)+[\\p{L}0-9](?:[\\p{L}0-9-]*[\\p{L}0-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]?|[\\p{L}0-9-]*[\\p{L}0-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) } }
步骤2:完善RegisterViewModel属性定义
确保你的ViewModel满足以下基础定义,核心是email和emailMessage都用@Published修饰,这样View才能监听到变化:
import Combine class RegisterViewModel: ObservableObject { // 用户输入的邮箱 @Published var email = "" // 邮箱校验提示信息,View直接监听该字段 @Published var emailMessage = "" // 你原来用到的类型别名 typealias ValidatePublisher = AnyPublisher<Bool, Never> // 持有订阅,避免信号被释放 private var cancellables = Set<AnyCancellable>() init() { // 订阅邮箱校验 publisher,触发校验逻辑 isEmailValidPublisher .sink(receiveValue: { _ in }) .store(in: &cancellables) } // 这里放修改后的isEmailValidPublisher }
步骤3:修改isEmailValidPublisher实现
把原来仅判断长度的逻辑,替换为「长度校验+正则校验」的组合逻辑:
private var isEmailValidPublisher: ValidatePublisher { $email .removeDuplicates() .map { email in // 先去除首尾空格换行 let trimmedEmail = email.trimmingCharacters(in: .whitespacesAndNewlines) // 先判断长度不小于10,再走正则校验 guard trimmedEmail.count >= 10 else { return false } return trimmedEmail.isValidEmail() } .handleEvents(receiveOutput: { [weak self] isValid in self?.emailMessage = isValid ? "" : "Invalid email" }) .eraseToAnyPublisher() }
步骤4:View层直接调用即可
你原本写的View层代码不需要任何修改,自动监听emailMessage的变化切换图标颜色:
Image(systemName: "envelope") .foregroundColor(registerVM.emailMessage != "" ? .red : .blue)
内容的提问来源于stack exchange,提问作者Mert Köksal
相关产品推荐
相关产品推荐

