28
25

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2017-01-19

最近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パターンを利用する場合なんかも書けたらと思います。

28
25
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
28
25

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?