How to make simple form validator in Swift
Khoa Pham

Khoa Pham @onmyway133

About: My apps https://onmyway133.com/apps/

Joined:
May 29, 2017

How to make simple form validator in Swift

Publish Date: Jun 25 '19
12 3

Sometimes we want to validate forms with many fields, for example name, phone, email, and with different rules. If validation fails, we show error message.

We can make simple Validator and Rule

class Validator {
    func validate(text: String, with rules: [Rule]) -> String? {
        return rules.compactMap({ $0.check(text) }).first
    }

    func validate(input: InputView, with rules: [Rule]) {
        guard let message = validate(text: input.textField.text ?? "", with: rules) else {
            input.messageLabel.isHidden = true
            return
        }

        input.messageLabel.isHidden = false
        input.messageLabel.text = message
    }
}

struct Rule {
    // Return nil if matches, error message otherwise
    let check: (String) -> String?

    static let notEmpty = Rule(check: {
        return $0.isEmpty ? "Must not be empty" : nil
    })

    static let validEmail = Rule(check: {
        let regex = #"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,64}"#

        let predicate = NSPredicate(format: "SELF MATCHES %@", regex)
        return predicate.evaluate(with: $0) ? nil : "Must have valid email"
    })

    static let countryCode = Rule(check: {
        let regex = #"^\+\d+.*"#

        let predicate = NSPredicate(format: "SELF MATCHES %@", regex)
        return predicate.evaluate(with: $0) ? nil : "Must have prefix country code"
    })
}
Enter fullscreen mode Exit fullscreen mode

Then we can use very expressively

let validator = Validator()
validator.validate(input: inputView, with: [.notEmpty, .validEmail])
Enter fullscreen mode Exit fullscreen mode

Then a few tests to make sure it works

class ValidatorTests: XCTestCase {
    let validator = Validator()

    func testEmpty() {
        XCTAssertNil(validator.validate(text: "a", with: [.notEmpty]))
        XCTAssertNotNil(validator.validate(text: "", with: [.notEmpty]))
    }

    func testEmail() {
        XCTAssertNil(validator.validate(text: "onmyway133@gmail.com", with: [.validEmail]))
        XCTAssertNotNil(validator.validate(text: "onmyway133", with: [.validEmail]))
        XCTAssertNotNil(validator.validate(text: "onmyway133.com", with: [.validEmail]))
    }

    func testCountryCode() {
        XCTAssertNil(validator.validate(text: "+47 11 222 333", with: [.countryCode]))
        XCTAssertNotNil(validator.validate(text: "11 222 333", with: [.countryCode]))
        XCTAssertNotNil(validator.validate(text: "47 11 222 333", with: [.countryCode]))
    }
}
Enter fullscreen mode Exit fullscreen mode

❤️ Support my apps ❤️

❤️❤️😇😍🤘❤️❤️

Comments 3 total

  • Saroar Khandoker
    Saroar KhandokerDec 23, 2019

    hi what is InputView? where is coming from ?

  • Texyz
    TexyzMay 23, 2020

    hi what is InputView? where is coming from ?

    • Netanel Draiman
      Netanel DraimanFeb 6, 2021

      InputView probably looks something like this:

      struct InputView {
          let textField: UITextField
          let messageLabel: UILabel
      }
      
      Enter fullscreen mode Exit fullscreen mode
Add comment