Drop in user input validation for iOS apps

Apple has been criticized in the past for its lack of security measures when it comes to app development, but a new report says that they may be making some changes.

In April 2019, Apple released a new set of security guidelines for iOS apps. One major change was the drop in user input validation from 2-3 lines to 1 line. This has been attributed to an increase in spam and scam attempts on the App Store which have increased exponentially over 2018 with a spike of 4 billion spam submissions last year alone.The “uitextfield validation error message swift” is a problem that has been present for a while. There are many causes of the issue, but there is one fix that can be done by developers.

Validator is a Swift-based user input validation framework. It’s comprehensive, extensible, and you’re in charge of the user interface.

Here’s how you may check whether an email address is valid:

let emailRule = ValidationRulePattern(pattern: EmailValidationPattern.standard, error: validationError) “[email protected],com” let emailRule = ValidationRulePattern(pattern: EmailValidationPattern.standard, error: validationError) “[email protected],com” .invalid = validate(emailRule) (validationError)

…or that a user is at least 18 years old:

allow eighteenYearsAgo to equal Date (). addingTimeInterval(-568024668) ValidationRuleComparison = drinkingAgeRule (min: eighteenYearsAgo, error: validationError) if dateOfBirth = Date; if dateOfBirth = Date; if date (). addingTimeInterval(-662695446) / dateOfBirth is 21 years old. .validate(rule: rule) / -> validate(rule: rule)

…or that a value falls inside a certain range:

if numericRule = ValidationRuleComparison; if numericRule = ValidationRuleComparison; if nu (min: 50, max: 100, error: validationError) 42.validate(numericRule) .invalid ->.invalid ->.invalid ->.invalid -> (validationError)

…or a valid Visa or American Express card number is entered into a text field:

ValidationRulePaymentCard(available); let cardRule = ValidationRulePaymentCard(available); ValidationError) (types: [.visa,.amex], error: validationError) payment .valid or.invalid(validationError) based on what’s in payment CardTextField.validate(cardRule) CardTextField

Features

  • Validation rules (x):
    • [x] Necessary
    • Equality (x)
    • [x] Similarities
    • Length [x] (min, max, range)
    • [x] Design (email, password constraints and more…)
    • Contains [x]
    • [x] URL
    • [x] Credit card (Luhn validated, accepted types)
    • [x] Situation (quickly write your own)
  • [x] Extensions of the Swift standard library type with a single API (not only strings!)
  • Extensions for UIKit elements (x)
  • [x] Types of open validation errors
  • [x] A protocol-oriented implementation that is open
  • [x] Comprehensive coverage of tests
  • [x] Code documentation that is extensive.

Demo

demo-vid

Installation

CocoaPods

‘Validator’ pod

Carthage

Carthage Compatible

“adamwaite/Validator” on github

Usage

Validator may use one or more ValidationRules to validate any Validatable type. A ValidationResult is returned when a validation operation matches either.valid or.invalid ([Error]).

let result = “[email protected],com” let rule = ValidationRulePattern(pattern: EmailValidationPattern.standard, error: validationError) confirm (rule: rule) / Note that Validator is the same as the above. validate([email protected],com], rule: rule), validate(input: “[email protected],com”), validate(input: “[email protected],com”), case.valid(let failures): print(failures.first?.message) case.invalid(let failures): print(failures.first?.message)

Validation Criteria

Required

Validates the existence of a type (not-nil).

ValidationRuleRequiredString?>: let stringRequiredRule = ValidationRuleRequiredString?>: let stringRequiredRule = ValidationRuleRequired (validationError error) ValidationRuleRequiredFloat?> let floatRequiredRule = ValidationRuleRequired (validationError error)

Note that you can’t use validate on a Validatable type that isn’t required (e.g. myString?). Because the optional chaining mechanism will avoid the call, validate(aRule…) is required. “thing”. It’s OK to use validate(rule: aRule…) instead of validate(rule: aRule…). Use Validator to check whether an option is necessary in this manner. confirm (input: anOptional, rule: aRule).

Equality

Checks whether one Equatable type is the same as another.

if staticEqualityRule = ValidationRuleEquality; if staticEqualityRule = ValidationRuleEquality; if static (target: “hello”, error: validationError) dynamicEqualityRule = ValidationRuleEquality(dynamicTarget: return textField.text?? “,” validationError)

Comparison

Compares a Comparable type to a maximum and minimum value.

let validationRuleComparison = comparisonRule (min: 5, max: 7, error: validationError)

Length

Validates if the length of a String is within a specified minimum, maximum, or range.

ValidationRuleLength = minLengthRule (min: 5, error: validationError) ValidationRuleLength = maxLengthRule (max: 5, error: validationError) ValidationRuleLength = rangeLengthRule (min: 5, max: 10, error: validationError)

Pattern

Checks whether a String matches a pattern.

ValidationRulePattern may be started with a String pattern or a ValidationPattern-compliant type. In the Patterns directory, Validator offers several typical patterns.

ValidationRulePattern: let emailRule = ValidationRulePattern: let emailRule = ValidationRuleP (pattern: EmailValidationPattern.standard, error: validationError) ValidationRulePattern(pattern: ContainsNumberValidationPattern(), error: someValidationErrorType) let digitRule = ValidationRulePattern(pattern: ContainsNumberValidationPattern(), error: someValidationErrorType) Hello there! ValidationRulePattern(pattern: “.*hello.*”, error: validationError) = ValidationRulePattern(pattern: “.*hello.*”, error: validationError) = ValidationRulePattern(pat

Contains

Validates that an Equatable type is contained inside the members of a SequenceType (where the Element of the SequenceType matches the input type).

let stringContainsRule = ValidationRuleContainsString, [String]>>>>>>>>>>>>>>>>>>>>>>>>>>>>> (sequence: [“hello,” “hi,” “hey,” validationError) let rule = ValidationRuleContainsInt, [Int]>>>>>>>>>>>>>>>>>>>>>>>>>> (error: validationError, sequence: [1, 2, 3])

URL

Validates a String against RFC 2396 to verify whether it’s a valid URL.

ValidationRuleURL = urlRule (error: validationError)

Card of Payment

Validates a String to verify whether it’s a genuine credit card number by running it via the Luhn check algorithm first, and then checking that it matches the format of many different payment card issuers.

public enumeration Int instance amex, mastercard, visa, maestro, dinersClub, jcb, discover, unionPay /…

To verify against any card type (just the Luhn check):

ValidationRulePaymentCard = anyCardRule (error: validationError)

To be validated against a list of acceptable card types (in this case, Visa, Mastercard, and American Express):

allow acceptedCards to be used PaymentCardValidationRule = ValidationRulePaymentCard (acceptedTypes: [.visa, .mastercard, .amex], error: validationError)

Condition

With a specified condition, validates a Validatable type.

ValidationRuleCondition[String]> let conditionRule = $0.contains(“Hello”) (error: validationError)

Make It Your Own

By adhering to the ValidationRule protocol, you may create your own validation rules:

ValidationRule typealias InputType func validate(input: InputType) -> Bool var error: ValidationError get get get get get get get get get get get get get get get get get get get get get get get get get get get get get get get get get get get get get get get get get get get get get get get get get get get get get get get get get get get get get get

Example:

struct HappyRule typealias InputType = String var error: ValidationError func validate(input: String) -> Bool return input == “” struct HappyRule typealias InputType = String var error: ValidationError func validate(input: String) -> Bool func validate(input: String) -> Bool func validate(input: String) -> Bool func validate

If your custom rule doesn’t currently exist in the library and you believe it may be valuable to others, submitting a pull request would be fantastic.

Validation Rules in Multiples (ValidationRuleSet)

Validation rules may be concatenated to form a ValidationRuleSet, which has a set of rules for validating a type.

ValidationRuleSet = var passwordRules () passwordRules.add minLengthRule = ValidationRuleLength(min: 5, error: validationError) (rule: minLengthRule) allow digit passwordRules.add Rule = ValidationRulePattern(pattern:.ContainsDigit, error: validationError) (rule: digitRule)

Validatable

The validate: method may be used to validate any type that follows the Validatable protocol.

/ Validate using just one rule: let result = “some string.” confirm (rule: aRule) / Use a set of criteria to validate: let result = 42.validate (rules: aRuleSet)

Extend Validatable Types

Make a new type validatable by extending the Validatable protocol.

a validatable extension a validatable extension a validatable extension a validatable extension a validatable

Note: Unless you need to verify many attributes, the implementation within the protocol extension should imply you don’t need to implement anything yourself.

ValidationResult

The ValidationResult enum is returned by the validate: method. ValidationResult may be in one of two different formats:

  1. .valid: The input meets the validation requirements.
  2. .invalid: The input does not meet the validation criteria. An array of types conforming to ValidationError is associated with an.invalid result.

Errors

Any ValidationError to be supplied with the result of a failed validation should be used to initialize rules.

Example:

let email: String enum struct User: Validatable struct User: Validatable struct User: Validatable struct User: Validatable struct User: ValidationErrors: String, ValidationError case emailInvalid = “Email address is invalid” var message return self.rawValue var message return self.rawValue var message return self.rawValue var message return self.rawValue var message return self.rawValue var message return self.rawValue var message return self.rawValu validate() -> validate() -> validate() -> validate() -> validate() return email.validate(rule: rule) ValidationResult let rule ValidationRulePattern(pattern:.emailAddress, error: ValidationErrors.emailInvalid) ValidationResult

UIKit Elements Validation

The validate: method may be used to verify the input of UIKit elements that adhere to ValidatableInterfaceElement.

textField.text = “I’m going to be validated” let textField = UITextField() textField.text = “I’m going to be validated” UISlider() is used to create a slider. / value = 0.3 Validate using just one rule: result = textField.validate(aRule) / Validate your data using a set of rules: if result = slider.validate; if result = slider.validate; if result (rules: aRuleSet)

Validate When The Input Is Changed

When the input changes in three stages, a ValidatableInterfaceElement may be set to automatically validate.

  1. Add a set of default rules to the mix:

    if textField = UI; if textField = UI; if text TextField() rules = ValidationRuleSet() rules var rules = ValidationRuleSet() rules var rules = ValidationRuleSet() rules textField add(rule: someRule) validation The rules are the rules.

  2. Add a closure that will trigger when the input changes:

    textField.validation case.valid: print(“valid!”) case.invalid(let failure) Handler = result in switch result Errors): allowing messages to be sent = failure Errors.map $message print(“invalid!”, messages) $message print(“invalid!”, messages) $message print(“invalid!”, messages) $message print(“invalid!”

  3. Begin by observing:

    ValidateTextFieldOnInputChange (enabled: true)

To cease observation, use.validateOnInputChange(enabled: false).

Extend Validatable UI Elements

Make an interface element validatable by extending the ValidatableInterfaceElement protocol.

Example:

typealias InputType = String var inputValue: String return text?? “” extension UITextField: ValidatableInterfaceElement typealias InputType = String var inputValue: String var inputValue: String var inputValue: String var inputValue: String var inputValue: String var inputValue: String validateOnInputChange func (enabled: Bool) ValidationEnabled switch if true: addTarget(self, action: #selector(validateInputChange), forControlEvents:.editingChanged); if false: removeTarget(self, action: #selector(validateInputChange); if true: removeTarget(self, action: #selector(validateInputChange case false: removeTarget(self, action: #selector(validateInputChange), forControlEvents:.editingChanged) @objc private func validateInputChange(_ sender: UITextField) @objc private func validateInputChange(_ sender: UITextField) @objc private func validateInputChange(_ sender: UITextField) @ sender.validate() is a function that checks whether or not a message has been sent.

Because of the implementation inside the protocol extension, you should only need to implement:

  1. The typealias is the name of the input that will be verified (e.g String for UITextField).
  2. The inputValue is the value that will be verified (e.g the text value for UITextField).
  3. To setup input-change observation, use the validateOnInputChange: method.

Examples

This repository contains an example project.

Contributing

Any and all ideas and recommendations are greatly appreciated! Please make sure that all current tests pass and that any new code is covered by unit tests. Any new features should be included to the README. Thanks!

@adamwaite

License

Any person who obtains a copy of this software and associated documentation files (the “Software”) is hereby granted permission to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit others to do so, subject to the following conditions:

All copies or significant parts of the Software must carry the above copyright notice and this permission notice.

THE SOFTWARE IS PROVIDED “AS IS,” WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE, WHETHER IN CONTRACT, TORT, OR OTHERWISE.

GitHub

https://github.com/adamwaite/Validator

The “SwiftUI textfield validation” is a bug that was introduced in iOS 10. This bug causes the user input for an iOS app to be dropped when the text field becomes too large. The issue can be fixed by using the “swiftui textfield validation“.

Related Tags

  • ios form validation best practices
  • swiftui form validation
  • text field validation in swift 5
  • swift string validation
  • swift validation rules