Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
25
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

posted at

updated at

Organization

[Swift] Validatorというライブラリを使ってValidationする

最近Swiftを書いているのですが、Validation周りってみなさんどうやっているんですかね?

小さなアプリケーションなら適当に自分でやれば良いような気もしますが、ある程度の規模なら自作するか、ライブラリを使うかになるんじゃないかと思います。

仕事ではSwift3を使用しているので、対応しているadamwaite/Validatorを試してみました。

ちなみに、他に有名なライブラリには以下があるようです。SwiftCopの方は追々試してみようかなー。

機能

READMEのFeaturesに書いてあります。
一応、必須、同値、数値の比較、文字列長、パターンマッチ、包含などのValidationRuleが予め用意されています。

ValidatorはUIKitなどの要素を拡張しているのですが、Swift歴が浅い自分にとってはライブラリのコードを読んで勉強になることが多く、面白かったです。

使い方

単純にValidation結果を返す

一番単純な使い方は、以下のようにRuleのインスタンスを作成し、validateメソッドを呼び出すかたちです。
(Boolを返すだけなので、メッセージは無視しています)

let rule = ValidationRuleLength(min: 0, max: 3, error: ValidationError(message: "エラー"))
rule.validate(input: "1234") // false

ValidationRuleLengthのコンストラクタに渡しているValidationErrorは独自に作成した(Validatorのサンプルにもありますが)構造体です。
エラーメッセージを持たせるようにしています。

import Foundation

struct ValidationError: Error {
    public let message: String
    public init(message errorMessage: String) {
        message = errorMessage
    }
}

Validation結果により処理を分ける

ValidatorはStringに対してもextensionしてValidationできるようになっているので、"1234".validate(rule: rule)といった呼び出しも可能です。
この場合は結果としてValidationResultというenumが返却されるので、validなのかinvalidなのかで処理を分ければいいです。

let rule = ValidationRuleLength(min: 0, max: 3, error: ValidationError(message: "エラー"))

let result = "1234".validate(rule: rule)

switch result {
  case .valid: print("😀")
  case .invalid(let failures): print(failures.first?.message)
}

ボタンが押されたタイミングでValidationする

ほとんど使い方は変わりません。
validだった際は"😎"を、invalidだった際はValidationErrorに詰め込んだエラーメッセージを、表示用のラベルに格納しています。

@IBOutlet weak var sample: UITextField!
@IBOutlet weak var sampleState: UILabel!
@IBAction func next(_ sender: UIButton) {
    let validationResult = sample.validate(rule: ValidationRuleLength(min: 0, max: 3, error: ValidationError(message: "💩")))
    switch validationResult {
    case .valid:
        sampleState.text = "😎"
    case .invalid(let errors):
        let error = errors.first as? ValidationError
        sampleState.text = error?.message ?? "😱"
    }
}

入力が変化したタイミングでValidationする

UITextFieldに対してValidationルールを追加し、入力が変更されたタイミングでのValidationを有効にします。validationHandlerにはValidation結果を受け取って表示用のラベルの値を更新する関数をクロージャとして渡します。

これで、UITextFieldの値が変更されたタイミングでリアルタイムにValidationが実施され、入力の状態("💩"か"😎")が切り替わるようになります。

@IBOutlet weak var sample: UITextField!
@IBOutlet weak var sampleState: UILabel!
let rule = ValidationRuleLength(min: 0, max: 3, error: ValidationError(message: "💩"))
override func viewDidLoad() {
    super.viewDidLoad()
    sample.validationRules = ValidationRuleSet()
    sample.validationRules?.add(rule: rule)
    // 入力が変更されたタイミングでのValidationを有効にする
    sample.validateOnInputChange(enabled: true)
    sample.validationHandler = { result in self.updateSampleValidationState(result: result) }
}

func updateSampleValidationState(result: ValidationResult) {
    switch result {
    case .valid:
        sampleState.text = "😎"
    case .invalid(let failures):
        sampleState.text = (failures.first as? ValidationError)?.message
    }
}

まとめ

最初はどう使えば良いのか戸惑いましたが、ライブラリ自体があまり大きくないのですぐに動きを把握することができました。どうなんでしょう?ライブラリとしてはそんなに悪くないかな、といった感じです。

別途自作Ruleの作り方やObserverパターンを利用する場合なんかも書けたらと思います。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
25
Help us understand the problem. What are the problem?