Swift 中的表单验证
Posted
技术标签:
【中文标题】Swift 中的表单验证【英文标题】:Form validation in Swift 【发布时间】:2016-07-18 03:37:18 【问题描述】:我最近开始了一个 Swift (2) ios 项目,并开始面临我的表单包含许多需要验证的字段的情况。
我的背景主要是 .Net,通过绑定和注释,可以在大型表单上以低维护的方式干净利落地实现表单验证,并且只需要几行代码。
自从使用 Swift 以来,我遇到了许多以各种方式详细说明验证的示例,但到目前为止,我遇到的所有事情似乎都非常耗费人力且维护成本很高,或者解释集中在进行验证本身而不是连接验证过程模型和视图有效。
例如:
Validating TextField Validate TextField as Double using extensions Validating email addresses我当前的解决方案定义了可以在验证字段输入时在函数中逐条检查的扩展,但是我觉得必须有一个更具可扩展性的解决方案来解决这个问题。
在验证可能有很多输入的表单时,可以采取哪些方法来提高可维护性?
例如,我们可以讨论一个假设的形式:
要求输入数字的文本字段 (Int)。 要求输入十进制数的文本字段(双精度)。 请求输入数字的文本字段,匹配特定规则(例如,是素数)(双)。 要求输入长度为 kL 的字符串的文本字段。 要求输入符合某些自定义规则的字符串的文本字段。当然,我不是在寻找真正满足上面列表的实现,而是在这些类型的场景中可扩展的方法或方法。
【问题讨论】:
【参考方案1】:“呃,表格”
-阿尔伯特·爱因斯坦爵士
是的,在 iOS 中构建可扩展的表单可能是一项艰巨而单调的工作。这就是为什么我有一个名为 FormViewController
的基类,它公开了一些常见的验证方法和一些可用于添加自定义验证的方法。
现在,下面的代码可能很长,我不会解释每一行。如果您有任何疑问,请以 cmets 的形式恢复。
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
【讨论】:
您的解决方案似乎是我应该采取的下一个合乎逻辑的步骤。感谢您的贡献。我特别喜欢它看起来非常独立,并展示了一些我会忽略的改进。 谢谢,有一些依赖项(如shakeView
和SHAKE_COUNT
)。我应该很快重构它。【参考方案2】:
EGFormValidator 库是用 Swift 3 编写的。它灵活且易于使用。
【讨论】:
【参考方案3】:目前看来不错的另一个选择是 SwiftValidator。 这是一个活跃的项目,我只需要几分钟就可以在我的项目中进行设置。
https://github.com/jpotts18/SwiftValidator
【讨论】:
【参考方案4】:尽管已经晚了 3 年,但我还是把它放在这里,供任何想要灵活和可扩展选项的人使用。据我所知,这将完全适合作为问题的答案。
请查看ATGValidator。
我没有在此处添加任何代码,因为框架链接中的自述文件包含大量相同的文档。
【讨论】:
以上是关于Swift 中的表单验证的主要内容,如果未能解决你的问题,请参考以下文章