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

如何重构Swift中onEditingChanged代码以实现协议复用?

重构Swift邮箱验证逻辑实现复用

方案1:将验证逻辑封装到FormModel中

把onEditingChanged内的逻辑提取为FormModel的方法,让所有需要邮箱验证的TextField都能直接调用。

修改FormModel代码:

class FormModel: ObservableObject {
    @Published var textEmail = ""
    @Published var isEmailValid = true
    
    // 原有邮箱验证规则
    func textFieldValidatorEmail(_ email: String) -> Bool {
        let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
        let emailPred = NSPredicate(format:"SELF MATCHES %@", emailRegEx)
        return emailPred.evaluate(with: email)
    }
    
    // 封装编辑结束后的验证逻辑
    func handleEmailEditingEnded() {
        if textFieldValidatorEmail(textEmail) {
            isEmailValid = true
        } else {
            isEmailValid = false
            textEmail = ""
        }
    }
}

View中调用简化为:

TextField("Email address", text: $formModel.textEmail, onEditingChanged: { isChanged in
    if !isChanged {
        formModel.handleEmailEditingEnded()
    }
})
if !formModel.isEmailValid {
    InvalidEmailView()
}

方案2:用ViewModifier实现通用验证逻辑

如果需要脱离FormModel、适配更多输入验证场景,推荐用SwiftUI的ViewModifier封装:

struct EmailValidationModifier: ViewModifier {
    @Binding var text: String
    @Binding var isValid: Bool
    let validator: (String) -> Bool
    
    func body(content: Content) -> some View {
        content
            .onEditingChanged { isChanged in
                if !isChanged {
                    isValid = validator(text)
                    if !isValid {
                        text = ""
                    }
                }
            }
    }
}

// 扩展View,简化调用
extension View {
    func emailValidation(text: Binding<String>, isValid: Binding<Bool>, validator: @escaping (String) -> Bool) -> some View {
        self.modifier(EmailValidationModifier(text: text, isValid: isValid, validator: validator))
    }
}

使用方式:

TextField("Email address", text: $formModel.textEmail)
    .emailValidation(text: $formModel.textEmail, isValid: $formModel.isEmailValid) { email in
        formModel.textFieldValidatorEmail(email)
    }
if !formModel.isEmailValid {
    InvalidEmailView()
}

方案3:提取为可复用闭包(快速复用场景)

如果只是临时复用同一段逻辑,可以直接把闭包定义为变量:

// 在View内定义复用闭包
let emailEditingHandler: (Bool, FormModel) -> Void = { isChanged, model in
    if !isChanged {
        model.isEmailValid = model.textFieldValidatorEmail(model.textEmail)
        if !model.isEmailValid {
            model.textEmail = ""
        }
    }
}

// 调用时直接传入
TextField("Email address", text: $formModel.textEmail, onEditingChanged: { isChanged in
    emailEditingHandler(isChanged, formModel)
})

三种方案适用场景:

  • 方案1:适合业务逻辑与模型绑定紧密的场景,逻辑内聚性强
  • 方案2:SwiftUI生态下的通用写法,支持灵活替换验证规则
  • 方案3:快速实现复用的轻量化方案,适合小范围临时复用

内容的提问来源于stack exchange,提问作者Ashutosh Mukherjee

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 12:25:36