Swift中的表单验证

Éli*_*tte 5 validation ios swift

我最近开始研究一个Swift(2)iOS项目,并开始面对我有许多需要验证的字段的表单.

我主要使用.Net背景,并且使用Binding和Annotations,可以在低维护的情况下以大型表单干净地实现表单验证,只需几行代码.

自从拥抱Swift以来,我遇到了许多以各种方式详细说明验证的例子,但到目前为止我遇到的所有内容似乎都非常耗费人力和高度维护,或者解释集中在进行验证本身而不是连接模型和模型之间的验证过程.有效的观点.

例如:

我当前的解决方案定义了在验证字段输入时可以在函数中按规则检查的扩展,但是我觉得必须有一个更具伸缩性的解决方案来解决这个问题.

在验证具有潜在许多输入的表单时,可以采取哪些方法来提高可维护性?

例如,我们可以讨论一个假设形式:

  • 请求输入数字的textField(Int).
  • 输入请求十进制数的textField(Double).
  • 请求输入数字的textField,匹配特定规则(例如,是素数)(Double).
  • 请求字符串的textField输入某个长度为kL.
  • 请求输入字符串的textField符合某些自定义规则.

当然,我并不是在寻找满足上面列表的实现,而是在这些类型的场景中可扩展的方法或方法.

avi*_*ara 15

"呃,形式"

- 艾伯特爱因斯坦先生

是的,在iOS中构建可扩展的表单可能是一项艰巨而单调的工作.这就是为什么我有一个名为a的基类FormViewController,它暴露了一些常用的验证方法和一些可用于添加自定义验证的方法.

现在,以下代码可能很长,我不打算解释每一行.如果您有任何疑问,请以评论的形式恢复.

import UIKit

typealias TextFieldPredicate = ( (String) -> (Bool) )

class FormViewController : UIViewController {

    var activeTextField : UITextField!

    private var mandatoryFields  = [UITextField]()
    private var emptyErrorMessages = [String]()

    private var emailFields = [UITextField]()
    private var emailErrorMessages = [String]()

    private var specialValidationFields = [UITextField]()
    private var specialValidationMethods = [TextFieldPredicate]()
    private var specialValidationErrorMessages = [String]()

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        registerForNotifications()
    }

    override func viewWillDisappear(animated: Bool) {
        super.viewWillDisappear(animated)
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


    private func registerForNotifications() {
        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(FormViewController.keyboardWillShow(_:)), name:UIKeyboardWillShowNotification, object: nil);
        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(FormViewController.keyboardWillHide(_:)), name:UIKeyboardWillHideNotification, object: nil);
    }

    func keyboardWillShow(notification:NSNotification?) {
        let keyboardSize = notification?.userInfo![UIKeyboardFrameBeginUserInfoKey]!.CGRectValue.size
        self.view.frame.origin.y = 0
        let keyboardYPosition = self.view.frame.size.height - keyboardSize!.height
        if keyboardYPosition < self.activeTextField!.frame.origin.y {
            UIView.animateWithDuration(GlobalConstants.AnimationTimes.SHORT) { () -> Void in
                self.view.frame.origin.y = self.view.frame.origin.y - keyboardSize!.height + 30
            }
        }
    }

    func keyboardWillHide(notification:NSNotification?) {
        UIView.animateWithDuration(GlobalConstants.AnimationTimes.SHORT) { () -> Void in
            self.view.frame.origin.y = 0
        }
    }

    func validateEmailForFields(emailTextFields:[UITextField]) -> [Bool] {
        var validatedBits = [Bool]()
        for emailTextField in emailTextFields {
            if let text = emailTextField.text where !text.isValidEmail() {
                emailTextField.shakeViewForTimes(WelcomeViewController.ERROR_SHAKE_COUNT)
                validatedBits.append(false)
            } else {
                validatedBits.append(true)
            }
        }
        return validatedBits
    }

    func validateSpecialTextFields(specialTextFields:[UITextField]) -> [Bool] {
        var validatedBits = [Bool]()
        for specialTextField in specialTextFields {
            let specialValidationMethod = self.specialValidationMethods[ specialValidationFields.indexOf(specialTextField)!]
            validatedBits.append(specialValidationMethod(specialTextField.text!))
        }
        return validatedBits
    }

    func validateEmptyFields(textFields : [UITextField]) -> [Bool] {
        var validatedBits = [Bool]()
        for textField in textFields {
            if let text = textField.text where text.isEmpty {
                textField.shakeViewForTimes(WelcomeViewController.ERROR_SHAKE_COUNT)
                validatedBits.append(false)
            } else {
                validatedBits.append(true)
            }
        }
        return validatedBits
    }

    func addMandatoryField(textField : UITextField, message : String) {
        self.mandatoryFields.append(textField)
        self.emptyErrorMessages.append(message)
    }

    func addEmailField(textField : UITextField , message : String) {
        textField.keyboardType = .EmailAddress
        self.emailFields.append(textField)
        self.emailErrorMessages.append(message)
    }

    func addSpecialValidationField(textField : UITextField , message : String, textFieldPredicate : TextFieldPredicate) {
        self.specialValidationErrorMessages.append(message)
        self.specialValidationMethods.append(textFieldPredicate)
        self.specialValidationFields.append(textField)
    }

    func errorMessageForEmptyTextField(textField : UITextField) throws -> String  {
        if self.mandatoryFields.contains(textField) {
            return self.emptyErrorMessages[self.mandatoryFields.indexOf(textField)!]
        } else {
            throw ValidationError.NonMandatoryTextField
        }
    }

    func errorMessageForMultipleEmptyErrors() -> String {
        return "Fields cannot be empty"
    }

    func errorMessageForMutipleEmailError() -> String {
        return "Invalid email addresses"
    }

    @IBAction func didTapFinishButton(sender:AnyObject?) {
        if let errorMessage = self.errorMessageAfterPerformingValidation() {
            self.showVisualFeedbackWithErrorMessage(errorMessage)
            return
        }
        self.didCompleteValidationSuccessfully()
    }

    func showVisualFeedbackWithErrorMessage(errorMessage : String) {
        fatalError("Implement this method")
    }

    func didCompleteValidationSuccessfully() {

    }

    func errorMessageAfterPerformingValidation() -> String? {
        if let errorMessage = self.errorMessageAfterPerformingEmptyValidations() {
            return errorMessage
        }
        if let errorMessage = self.errorMessageAfterPerformingEmailValidations() {
            return errorMessage
        }
        if let errorMessage = self.errorMessageAfterPerformingSpecialValidations() {
            return errorMessage
        }
        return nil
    }

    private func errorMessageAfterPerformingEmptyValidations() -> String? {
        let emptyValidationBits = self.performEmptyValidations()
        var index = 0
        var errorCount = 0
        var errorMessage : String?
        for validation in emptyValidationBits {
            if !validation {
                errorMessage = self.emptyErrorMessages[index]
                errorCount += 1
            }
            if errorCount > 1 {
                return self.errorMessageForMultipleEmptyErrors()
            }
            index = index + 1
        }
        return errorMessage
    }

    private func errorMessageAfterPerformingEmailValidations() -> String? {
        let emptyValidationBits = self.performEmailValidations()
        var index = 0
        var errorCount = 0
        var errorMessage : String?
        for validation in emptyValidationBits {
            if !validation {
                errorMessage = self.emailErrorMessages[index]
                errorCount += 1
            }
            if errorCount > 1 {
                return self.errorMessageForMutipleEmailError()
            }
            index = index + 1
        }
        return errorMessage
    }

    private func errorMessageAfterPerformingSpecialValidations() -> String? {
        let emptyValidationBits = self.performSpecialValidations()
        var index = 0
        for validation in emptyValidationBits {
            if !validation {
                return self.specialValidationErrorMessages[index]
            }
            index = index + 1
        }
        return nil
    }

    func performEqualValidationsForTextField(textField : UITextField, anotherTextField : UITextField) -> Bool {
        return textField.text! == anotherTextField.text!
    }


    private func performEmptyValidations() -> [Bool] {
        return validateEmptyFields(self.mandatoryFields)
    }
    private func performEmailValidations() -> [Bool] {
        return validateEmailForFields(self.emailFields)
    }
    private func performSpecialValidations() -> [Bool] {
        return validateSpecialTextFields(self.specialValidationFields)
    }


}

extension FormViewController : UITextFieldDelegate {
    func textFieldDidBeginEditing(textField: UITextField) {
        self.activeTextField = textField
    }
    func textFieldDidEndEditing(textField: UITextField) {
        self.activeTextField = nil
    }
}

enum ValidationError : ErrorType {
    case NonMandatoryTextField
}
Run Code Online (Sandbox Code Playgroud)