ATGValidator
ATGValidator是一个针对用户输入数据验证过程中遇到的大部分常见问题而编写的验证框架。
您可以直接用它来验证不同类型的数据,或验证UI组件,如UITextfield或UITextView,甚至可以为自定义UI元素添加验证支持。您无需继承原生组件以获得验证支持。UITextField和UITextView自带验证支持,为其他元素添加支持的简单方式是添加一个遵循ValidatableInterface
协议的扩展。
最好的一点是,您将获得一个强大的表单验证器,它可以整合添加到其中的所有UI组件的验证结果。
示例项目
您可以在这里找到具有表单验证的示例项目。
安装
Carthage
ATGValidator
可以使用Carthage进行安装。为此,只需将以下行添加到您的Cartfile
中:
github "altayer-digital/ATGValidator" ~> 1.0.0
Cocoapods
要使用Cocoapods与ATGValidator
,请将以下行添加到Podfile
中:
pod 'ATGValidator', '~> 1.0'
用法
添加验证的第一步是在ui元素上设置验证规则。任何符合ValidatableInterface
的UI元素都可以接受一个规则数组的设置。
textfield.validationRules = [
CharacterSetRule.containsUpperCase(),
CharacterSetRule.containsLowerCase(),
CharacterSetRule.containsNumber(),
CharacterSetRule.containsSymbols()
]
为了验证单个textfield或textview,您可以在textfield/textview上设置一个validationHandler
闭包。这将每次在字段上进行验证并且结果准备好应用时执行。如果验证结果为失败,则会通过结果对象传递一个错误数组。
textfield.validationHandler = { result in
print(result.status, result.errors)
}
您可以通过在ui元素上调用validateOnInputChange
或validateOnFocusLoss
来使其在相应的事件上执行验证。
textfield.validateOnInputChange(true)
textfield.validateOnFocusLoss(true)
如果您需要聚合多个ui元素的验证,您需要创建一个FormValidator
实例,并将所有所需的元素添加到表单验证器中。
let formValidator = FormValidator(handler: { result in
print(result.status, result.errors)
})
formValidator.add(textfield)
当将项添加到表单验证器时,默认情况下将在这些项失去焦点时执行验证。但您可以通过在将项添加到表单验证器时提及验证策略来更改此行为。
formValidator.add(textfield, policy: .onInputChange) // or .onFocusLoss or .none
每当字段的数据发生相应状态变化时,表单验证器的处理闭包将自动以聚合结果执行。
如果您需要在需求时执行验证,可以使用方法validateForm(shouldInvokeElementHandlers:completion:)
来在需要时执行验证。
规则
框架一开始就提供了6种类型的规则。对于所有规则,您可以在初始化时设置一个自定义错误,或调用辅助方法with(error:)->Rule
或with(errorMessage:)->Rule
稍后设置它。如果没有,所有规则都有它们自己来自ValidationError
枚举的默认错误。下面是每个规则的说明。
EqualityRule
此规则用于检查类型的值是否等于提供的值。
您可以通过将待检查的值传递给初始化器来创建一个相等性规则。可选地,您可以传递模式(equal
、notEqual
)和错误对象,以便在验证失败时返回。
let rule = EqualityRule(value: "text_to_be_verified")
// or
let rule = EqualityRule(value: "shouldn't_be_equal_text", mode: .notEqual, error: ValidationError.equal)
默认错误
notEqual
模式下的equal
错误。notEqual
模式下的equal
错误。
RangeRule
使用此规则,您可以使用这个规则来检查一个值是否位于特定的范围内。
let rangeRule = RangeRule(min: 200, max: 299)
默认错误:valueOutOfRange
StringLengthRule
使用此规则可以检查字符串长度是否符合要求。您可以传入是否要去除空白字符和忽略特定字符集。
let lengthInRangeRule = StringLengthRule(min: 5, max: 10, trimWhiteSpace: true, ignoreCharactersIn: CharacterSet.symbols)
let minLengthRule = StringLengthRule.min(5)
let maxLengthRule = StringLengthRule.max(5)
let equalLengthRule = StringLengthRule.equal(to: 6)
let requiredStringRule = StringLengthRule.required()
默认错误
- 默认:
lengthOutOfRange
- 最小值:
shorterThanMinimumLength
- 最大值:
longerThanMaximumLength
- 相等:
notEqual
- 必填:
shorterThanMinimumLength
StringRegexRule
此规则允许您对字符串执行正则表达式匹配。您可以选择是否去除空白字符。
let regexRule = StringRegexRule(regex: "^[0-9]*$")
let emailRule = StringRegexRule.email
let containsNumber = StringRegexRule.containsNumber()
let containsNumbersMinMax = StringRegexRule.containsNumber(min: 2, max: 4)
let containsUpperCase = StringRegexRule.containsUpperCase()
let containsUpperCaseMinMax = StringRegexRule.containsUpperCase(min: 1, max: 2)
let containsLowerCase = StringRegexRule.containsLowerCase()
let containsLowerCaseMinMax = StringRegexRule.containsLowerCase(min: 1, max: 2)
let numbersOnly = StringRegexRule.numbersOnly
let lowerCaseOnly = StringRegexRule.lowerCaseOnly
let upperCaseOnly = StringRegexRule.upperCaseOnly
默认错误
- 默认:
regexMismatch
- 电子邮件:
invalidEmail
- 包含数字:
numberNotFound
- 包含大写字母:
upperCaseNotFound
- 包含小写字母:
lowerCaseNotFound
- 全数字:
invalidType
- 只有小写字母:
invalidType
- 只有大写字母:
invalidType
StringValueMatchRule
可以使用此规则检查两个文本字段的值是否相同。一个理想的例子是当检查密码字段和确认密码字段的值是否相同。
let passwordTextfield: UITextField?
let confirmPasswordTextfield: UITextField?
let valueMatchRule = StringValueMatchRule(base: passwordTextfield)
confirmPasswordTextfield.validationRules = [valueMatchRule]
默认错误:notEqual
PaymentCardRule
支付卡规则可用于检查提供的卡号是否为有效的支付卡号。结合Luhn算法和正则表达式进行匹配,用于检查提供卡号的的有效性。可以通过指定的卡类型启动此规则,如果没有指定,将检查所有可用的卡类型。可用的卡类型包括:
- 美国运通
- 万事达卡
- Maestro
- 维萨卡
- 维萨电子卡
- 发现卡
- 大莱卡
let cardRule = PaymentCardRule(acceptedTypes: [.amex, .mastercard, .visa, .discover])
// or
let cardRule = PaymentCardRule()
textfield.validationRules = [cardRule]
textfield.validationHandler = { result in
if let suggestedType = result.value as? PaymentCardType {
// This is a suggestion from the framework from the input you entered.
// Please note that having a suggested card type does not mean it's validation is success.
// You need to handle success/failure separately outside this confition.
}
}
textfield.validateOnInputChange(true)
默认错误
- 如果卡号无效:
invalidPaymentCardNumber
- 如果卡号有效,但不属于受支持的类型:
paymentCardNotSupported
为了在输入卡号时识别卡类型,请使用 Result
对象中的 value
字段。如果可以从输入中建议卡类型,则规则将用卡类型填充 Result.value
字段,否则将用输入填充。请注意,在规则开始寻找卡类型建议之前,需要输入至少4个字符。
高级应用
以下展示了如何直接验证常见数据类型:
"Example with 1 number".satisfyAll(rules: [CharacterSetRule.containsNumber()]).status // success
"Example with more than 20 characters".satisfyAll(rules: [StringLengthRule.max(20)]).status // failure
472.satisfyAll(rules: [EqualityRule(value: 472.5)]) // failure
301.satisfyAny(rules: [RangeRule(min: 200, max: 299), EqualityRule(value: 304)]) // failure
200.satisfyAny(rules: [RangeRule(min: 200, max: 299), EqualityRule(value: 304)]) // success
有关验证UI组件内容的示例,请看以下内容:
textfield.validationRules = [CharacterSetRule.lowerCaseOnly(ignoreCharactersIn: .whitespaces)]
textfield.validationHandler = { result in
// This block will be executed with relevant result whenever validation is done.
print(result.status) // success
}
// Below line is to manually trigger validation.
textfield.validateTextField()
为了使用表单验证器,我们需要创建一个FormValidator
实例,并将所需UI元素添加到表单验证器中。我们可以直接调用validateForm
方法,或者将处理闭包关联到表单验证器,它在任何添加的UI元素的值更改时将被调用。
let formValidator = FormValidator()
formValidator.add(textfield)
// Add more ui elements here.
formValidator.validateForm { result in
print(result)
}
Validatable
Validatable 是任何可验证的数据类型都遵循的基本协议。在Swift中最常用到的类型直接遵循 Validatable 协议。以下是直接遵循 Validatable 协议的所有数据类型的列表:
- String(字符串)
- Bool(布尔值)
- Int(整数)
- Double(双精度浮点数)
- Float(单精度浮点数)
- CGFloat(任意精度浮点数)
- Date(日期)
如果你想要为其他任何类型添加验证支持,你可以通过使其遵循 validatable 协议来做到。
ValidatableInterface
如果任何自定义UI元素需要支持验证,它需要遵循 ValidatableInterface
协议。默认情况下,ATGValidator 已经为 UITextField
和 UITextView
增加了此协议。请注意,ValidatableInterface
协议遵循 Validatable
协议。请参阅以下 UITextField
的示例以了解如何实现遵从。
extension UITextField: ValidatableInterface {
public var inputValue: Any {
return text ?? ""
}
public func validateOnInputChange(_ validate: Bool) {
if validate {
addTarget(self, action: #selector(validateTextField), for: .editingChanged)
} else {
removeTarget(self, action: #selector(validateTextField), for: .editingChanged)
}
}
public func validateOnFocusLoss(_ validate: Bool) {
if validate {
addTarget(self, action: #selector(validateTextField), for: .editingDidEnd)
addTarget(self, action: #selector(validateTextField), for: .editingDidEndOnExit)
} else {
removeTarget(self, action: #selector(validateTextField), for: .editingDidEnd)
removeTarget(self, action: #selector(validateTextField), for: .editingDidEndOnExit)
}
}
@objc public func validateTextField() {
guard let rules = validationRules else {
return
}
var result = satisfyAll(rules: rules)
if result.status == .success {
validValue = result.value
} else if let value = validValue {
result.value = value
}
validationHandler?(result)
formHandler?(result)
}
}
自定义错误
ValidationError
是一个枚举,包含所有默认验证错误。如果您不想定义额外的错误对象,只需要传递自定义验证错误字符串,请使用 ValidationError.custom(errorMessage: String)
。在 Rule
中有几个辅助方法可以帮助轻松设置自定义错误。具体如下;
var emailRule = StringRegexRule.email
emailRule = emailRule.with(error: CustomErrorThatConformsToErrorProtocol())
// or
emailRule = emailRule.with(errorMessage: "Email is not correct..!")
ValidatorCache
这是一个自定义的内存存储,用于保存所有规则、表单处理器和验证处理器闭包。请随意探索其实现方式。
致谢
当我们面对寻找良好验证框架用于应用程序的任务时,我们经历了探索阶段以找到可用的开源库,并最终找到了最佳可用解决方案。如果您处于同样的情况,您必须知道它是哪一个。不是别的,正是 Adam Waite 编写的惊人框架 Validator。如果您还没有看到它,请访问该仓库并查看。
Validator 广泛使用了泛型,这是框架工作的核心。这使得我们无法将各种用户界面元素结合起来,并从中获取统一的验证结果。而我们确实需要在我们的项目中实现表单验证。
因此,我们开始编写一个以协议为骨干的框架,并使用表单验证作为我们想要实现的主要目标。这就是成果,ATGValidator。请注意,核心概念受到Validator 框架的极大影响,并且我们想要向 Adam Waite 对其出色的贡献表示感谢。
版权和许可证
ATGValidator支持MIT许可证。有关更多信息,请参阅LICENSE.md
:点击这里。