You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:47:55