2
1

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 1 year has passed since last update.

[Swift] 文字入力バリデーションを実装する(iOS)

Last updated at Posted at 2021-09-02

はじめに

TextField等の入力フォームで受け取った文字列をそのままサーバー側に投げるのは、サーバへの負担となってしまうのでなるべく避けたいところです。
そこで明らかに無効な入力があった場合、アプリ側で弾くことができるよう簡易的なバリデーション機能を設けることにしました。

チェック対象

  • Password

記事を分かりやすくするため、パスワードのバリデーションのみを考えることにします。

必要な要件

  • 英数字のみ
  • 大文字小文字の制限は設けない
  • 文字数は6~8

よくある簡易的なパスワードという感じです。

実装

上記のようなフォームに入力した場合を想定してつくります。

コード

import Foundation

// ①
enum ValidationResult {
    case valid
    case dataIsEmpty(section: String)
    case lengthInvalid(section: String, min: Int, max: Int)
    case invalidFormat(section: String)
    
    // ②
    var isValid: Bool {
        switch self {
        case .valid:
            return true
        case .dataIsEmpty:
            return false
        case .lengthInvalid:
            return false
        case .invalidFormat:
            return false
        }
    }
    
    // ③
    var errorMessage: String {
        switch self {
        case .valid:
            return ""
        case .dataIsEmpty(let section):
            return "\(section)の入力がありません"
        case .lengthInvalid(let section, let min, let max):
            return "\(section)\(min)文字以上\(max)文字以下で入力してください"
        case .invalidFormat(let section):
            return "\(section)に使用できない文字が含まれています"
        }
    }
}

final class Validator {
    
    static let shared: Validator = .init()
    private init() {}
    
    // ④
    func passwordCheck(with _password: String?, min: Int, max: Int) -> ValidationResult {
        
        // ⑤
        guard let _password = _password, !_password.isEmpty else {
            return .dataIsEmpty(section: "パスワード")
        }
        
        // ⑥
        guard _password.count >= min && _password.count <= max else {
            return .lengthInvalid(section: "パスワード", min: min, max: max)
        }
        
        // ⑦
        let pattern = "[^a-zA-Z0-9]"
        if _password.range(of: pattern, options: .regularExpression) != nil {
            return .invalidFormat(section: "パスワード")
        }
        
        // ⑧
        return .valid
    }
    
}

解説

① ValidationResult

enum ValidationResultを定義し、バリデーションの結果をenumで受け取ります。
caseはチェックする内容ごとに用意すると良いです。

  • case valid (有効)
  • case dataIsEmpty (空入力)
  • case lengthInvalid (文字数)
  • case invalidFormat (指定外の文字の使用)

今回はこの4つを用意しています。

バリデーションチェックの結果によってこのいずれかを返すことになります。

② isValid: Bool

enumにBool型のisValidを持たせています。
これは好みによると思いますが、私は呼び出し側でguardifなどの条件分岐が書きやすくなるので用意しています。

③ errorMessage: String

enumにString型のerrorMessageを持たせています。
selfで条件分岐し、それぞれのケースに対応したStringを保持します。

呼び出し側はUIAlertControllererrorMessageを渡して表示するなどして使用します。

④ passwordCheck

この関数を外部から呼ぶことになります。
引数で入力された文字列文字数の最小値文字数の最大値を受け取ります。
今回はTextField.Textをそのまま受け取る想定ですのでString?型にしています。

処理した戻り値は事前に用意したValidationResultです。

⑤ 空文字の除外

受け取ったString?がnilもしくは""だった場合、ValidationResult.dataIsEmptyを返します。
その際、(section: "パスワード")とし、エラーメッセージに反映させたい文字列も一緒に渡しています。

(2022.06.30追記)nilチェックだけでなく、!_password.isEmptyを加えることで、""といった空文字もここで止めています。

このようにすることで、ユーザー名やメールアドレスといった他のバリデーションを行いたいときに、sectionの文字列を変更するだけで良くなります。

※2022.06.30追記
isEmptyのチェックは不要では?と編集リクエストをいただきました。
コメント欄にて返事をさせていただきました。

⑥ 文字数チェック

受け取った文字列が、決められた文字数の範囲内かどうかを確認します。
範囲外の場合はValidationResult.lengthInvalidを返します。
ここでも同じようにエラーメッセージに渡したい情報を用意しています。

⑦ 不正な文字を使用していないかの確認

受け取った文字列に、使用できないものが含まれていないかの確認をします。

rangeメソッドを正規表現で使用し、nilで無かった場合(不正な文字が検出された場合)、
ValidationResult. invalidFormatを返します。

⑧ 問題ない場合

ValidationResult.validを返します。

呼び出し側

コード

以下のような形で呼び出すことができます。

// フォームに入力された文字列と仮定
let textFieldText: String? = "dsna-uh/"

let result = Validator.shared.passwordCheck(with: textFieldText, min: 6, max: 8)

print(result.isValid) // false
print(result.errorMessage) // パスワードに使用できない文字が含まれています

isValidを使用してswitchで条件分岐させるような書き方もできます。

let result = Validator.shared.passwordCheck(with: textFieldText, min: 6, max: 8)

switch result.isValid {
case true:
    // 問題なかった場合の処理
case false:
    // 問題があった場合の処理
}

終わりに

ここまで読んでいただきありがとうございました。
試行錯誤しながら実装したものなので、良くない部分やもっとスマートな記述方法があったりするかもしれませんが、これからバリデーションを実装しようとしている方の参考になれば幸いです。

上述のコードはPlaygroundで動作しますので、ぜひお試しください。

2
1
1

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
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?