Swift中如何在结构体内部验证属性并通过闭包返回结果
实现方案:结构体内部验证+闭包回调通知
这个需求其实很适合用Swift结构体的属性观察者+闭包回调来实现,既把验证逻辑封装在结构体内部,又能及时把结果通知给外部控制按钮状态。我给你一步步拆解具体实现:
1. 重构State结构体,封装验证逻辑与回调闭包
首先我们修改结构体,让它能监听属性变化、内部完成验证,并通过闭包把结果抛给外部:
struct State { // 改为可变属性,配合didSet监听编辑变化 var email: String { didSet { // 属性更新时自动触发验证并通知 validateAndNotify() } } var phoneNumber: String { didSet { validateAndNotify() } } // 定义回调闭包:外部通过这个闭包接收验证结果 var validationChangedHandler: ((Bool) -> Void)? // 初始化方法,保留原有传参逻辑 init(email: String, phoneNumber: String) { self.email = email self.phoneNumber = phoneNumber // 初始化时立即执行一次验证,确保初始状态正确 validateAndNotify() } // MARK: - 内部验证逻辑 private func validateEmail() -> Bool { // 这里用通用邮箱正则,你可以根据业务替换成更严谨的规则 let emailRegex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}" let predicate = NSPredicate(format:"SELF MATCHES %@", emailRegex) return predicate.evaluate(with: email) } private func validatePhoneNumber() -> Bool { // 示例为国内手机号规则,可根据你的需求调整 let phoneRegex = "^1[3-9]\\d{9}$" let predicate = NSPredicate(format:"SELF MATCHES %@", phoneRegex) return predicate.evaluate(with: phoneNumber) } // 整体验证是否通过 private var isValid: Bool { return validateEmail() && validatePhoneNumber() } // 验证完成后通知外部 private func validateAndNotify() { validationChangedHandler?(isValid) } }
2. 在视图控制器中使用State,绑定文本框与按钮状态
接下来在你的视图控制器里,初始化State实例,设置回调闭包控制按钮,并在文本框代理方法中更新结构体属性:
class YourViewController: UIViewController { @IBOutlet weak var emailTextField: UITextField! @IBOutlet weak var phoneTextField: UITextField! @IBOutlet weak var submitButton: UIButton! // 持有State实例 private var userState: State! override func viewDidLoad() { super.viewDidLoad() // 初始化State,传入原有初始值 userState = State(email: "email", phoneNumber: "021000000") // 设置验证回调:根据结果启用/禁用按钮 userState.validationChangedHandler = { [weak self] isValid in // 用weak self避免循环引用 self?.submitButton.isEnabled = isValid } // 绑定文本框代理 emailTextField.delegate = self phoneTextField.delegate = self } } // MARK: - UITextFieldDelegate 实现 extension YourViewController: UITextFieldDelegate { func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { // 获取文本框更新后的内容 guard let currentText = textField.text else { return true } let updatedText = (currentText as NSString).replacingCharacters(in: range, with: string) // 根据文本框类型更新State对应的属性 if textField == emailTextField { userState.email = updatedText } else if textField == phoneTextField { userState.phoneNumber = updatedText } return true } }
3. 关键细节说明
- 封装性:验证逻辑完全放在
State内部,外部不需要关心具体怎么验证,只需要处理结果,符合单一职责原则。 - 自动触发验证:通过
didSet属性观察者,每次用户编辑文本框更新属性时,都会自动触发验证并通知外部,无需手动调用验证方法。 - 避免循环引用:回调闭包中使用
[weak self],防止视图控制器和State互相持有导致内存泄漏。 - 扩展性:如果后续需要返回具体的错误原因(比如邮箱格式错了还是手机号错了),可以把闭包的参数改成自定义枚举(比如
ValidationResult),让回调信息更丰富。
这样实现后,当用户编辑文本框时,State会自动完成验证,通过闭包通知你更新按钮状态,同时验证后的State实例也可以直接传递给其他类使用。
内容的提问来源于stack exchange,提问作者iOSDeveloper
相关产品推荐
相关产品推荐

