DEV Community

Khoa Pham
Khoa Pham

Posted on • Edited on

8 1

How to make simple form validator in Swift

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 ❤️

❤️❤️😇😍🤘❤️❤️

Image of Docusign

🛠️ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more

Top comments (3)

Collapse
 
saroar profile image
Saroar Khandoker

hi what is InputView? where is coming from ?

Collapse
 
texyz profile image
Texyz

hi what is InputView? where is coming from ?

Collapse
 
nexxado profile image
Netanel Draiman • Edited

InputView probably looks something like this:

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

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Immerse yourself in a wealth of knowledge with this piece, supported by the inclusive DEV Community—every developer, no matter where they are in their journey, is invited to contribute to our collective wisdom.

A simple “thank you” goes a long way—express your gratitude below in the comments!

Gathering insights enriches our journey on DEV and fortifies our community ties. Did you find this article valuable? Taking a moment to thank the author can have a significant impact.

Okay