iOS
 Computer >> コンピューター >  >> プログラミング >> iOS

Swiftでテキストフィールドの入力を検証する汎用バリデーションの作成方法

はじめに

iOSアプリを開発していると、ユーザー登録画面やログイン画面など、複数の画面で同じような入力バリデーション(検証)コードを繰り返し書いてしまうことがよくあります。入力フィールドごとに同じ処理を毎回記述するのは手間がかかりますし、うっかりミスが混入する原因にもなります。

良質な設計の観点からは、各フィールドごとに個別のバリデーションを書くのではなく、汎用的なバリデーション関数を用意することが推奨されます。この記事では、テキストフィールド向けの汎用バリデーションライブラリを実装する方法を、ステップごとに解説します。

汎用バリデーションライブラリのメリット

  • 再利用性:どの画面・機能でも同じコードを使い回せる
  • ミスの削減:同じロジックを何度も書かないため、人的エラーが減る
  • 導入が簡単:セットアップと既存コードへの組み込みが短時間で済む
  • 保守性:1つの関数を修正すれば、すべての箇所に変更が反映される

作成するもの

今回は「Validation」という名前のプロジェクトで、バリデーションライブラリ本体と、それを使って4つの入力フィールド(氏名・メールアドレス・パスワード・電話番号)を検証するサンプルアプリを作成します。ライブラリは汎用的に設計されており、必要に応じて自由に拡張できます。

ステップ1:プロジェクトの作成

Xcodeを開き、「Single View Application」を選択して、プロジェクト名を「Validation」にします。

ステップ2:バリデーション用クラスの追加

新しいファイルを作成します。「File」→「New File」→「Swift File」の順に選択し、「Validation.swift」という名前で保存してください。

ステップ3:UIの配置

Main.storyboardを開き、以下のようにUIを配置します。

Swiftでテキストフィールドの入力を検証する汎用バリデーションの作成方法

ここでは4つのテキストフィールドと1つのボタンを配置しました。すべての項目を入力して「Validate」ボタンをタップすると、各フィールドが検証され、誤りのある項目が出力されます。すべて正しければ「All fields are correct」と表示されます。

ステップ4:IBActionとIBOutletの接続

ボタンには@IBActionを、各入力フィールドには@IBOutletを接続します。

import UIKit
class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    @IBOutlet var validateNameTxtFld: UITextField!
    @IBOutlet var validateEmailTxtFld: UITextField!
    @IBOutlet var validatePasswordTxtFld: UITextField!
    @IBOutlet var validatePhoneTxtFld: UITextField!
    @IBAction func validateBtn(_ sender: Any) {
    }
}

ステップ5:Validation.swiftに検証ロジックを記述

Validation.swiftを開き、バリデーション本体のコードを追加します。以下のコードをコピー&ペーストしてください。

import Foundation
class Validation {
    public func validateName(name: String) -> Bool {
        // 文字数は最小3文字・最大18文字。必要に応じて変更できます。
        let nameRegex = "^\\w{3,18}$"
        let trimmedString = name.trimmingCharacters(in: .whitespaces)
        let validateName = NSPredicate(format: "SELF MATCHES %@", nameRegex)
        let isValidateName = validateName.evaluate(with: trimmedString)
        return isValidateName
    }
    public func validaPhoneNumber(phoneNumber: String) -> Bool {
        let phoneNumberRegex = "^[6-9]\\d{9}$"
        let trimmedString = phoneNumber.trimmingCharacters(in: .whitespaces)
        let validatePhone = NSPredicate(format: "SELF MATCHES %@", phoneNumberRegex)
        let isValidPhone = validatePhone.evaluate(with: trimmedString)
        return isValidPhone
    }
    public func validateEmailId(emailID: String) -> Bool {
        let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
        let trimmedString = emailID.trimmingCharacters(in: .whitespaces)
        let validateEmail = NSPredicate(format: "SELF MATCHES %@", emailRegEx)
        let isValidateEmail = validateEmail.evaluate(with: trimmedString)
        return isValidateEmail
    }
    public func validatePassword(password: String) -> Bool {
        // 最小8文字で、英字を1文字以上・数字を1文字以上含む
        let passRegEx = "^(?=.*[A-Za-z])(?=.*\\d)[A-Za-z\\d]{8}$"
        let trimmedString = password.trimmingCharacters(in: .whitespaces)
        let validatePassword = NSPredicate(format: "SELF MATCHES %@", passRegEx)
        let isValidatePass = validatePassword.evaluate(with: trimmedString)
        return isValidatePass
    }
    public func validateAnyOtherTextField(otherField: String) -> Bool {
        let otherRegexString = "Your regex String"
        let trimmedString = otherField.trimmingCharacters(in: .whitespaces)
        let validateOtherString = NSPredicate(format: "SELF MATCHES %@", otherRegexString)
        let isValidateOtherString = validateOtherString.evaluate(with: trimmedString)
        return isValidateOtherString
    }
}

各入力項目に対応する正規表現(RegexString)は、要件に応じて自由にカスタマイズできます。たとえば日本の電話番号形式に対応させたい場合も、正規表現を差し替えるだけで済みます。

ステップ6:ViewControllerからValidationクラスを使う

ViewController.swiftを開き、Validationクラスのインスタンスを作成します。

var validation = Validation()

続いて、guard文を使って各入力フィールドの値を安全に取り出します。

guard let name = validateNameTxtFld.text,
      let email = validateEmailTxtFld.text,
      let password = validatePasswordTxtFld.text,
      let phone = validatePhoneTxtFld.text else {
    return
}

ステップ7:各フィールドに対して検証を実行

各フィールドに対してバリデーション関数を呼び出し、falseが返ってきた場合はエラーメッセージを出力して処理を中断します。

let isValidateName = self.validation.validateName(name: name)
if (isValidateName == false) {
    print("Incorrect Name")
    return
}
let isValidateEmail = self.validation.validateEmailId(emailID: email)
if (isValidateEmail == false) {
    print("Incorrect Email")
    return
}
let isValidatePass = self.validation.validatePassword(password: password)
if (isValidatePass == false) {
    print("Incorrect Pass")
    return
}
let isValidatePhone = self.validation.validaPhoneNumber(phoneNumber: phone)
if (isValidatePhone == false) {
    print("Incorrect Phone")
    return
}

ステップ8:すべての項目が正しい場合の処理

すべての検証を通過したら、「All fields are correct」を出力します。

if (isValidateName == true && isValidateEmail == true && isValidatePass == true && isValidatePhone == true) {
    print("All fields are correct")
}

※最終判定では「すべての項目が有効であること」を確認したいため、論理積(&&)を使用します。不正な項目はすでに早期リターンで除外されているため、ここで確実に意図した結果が得られます。

完成!ViewController.swiftの最終コード

import UIKit
class ViewController: UIViewController {
    var validation = Validation()
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    @IBOutlet var validateNameTxtFld: UITextField!
    @IBOutlet var validateEmailTxtFld: UITextField!
    @IBOutlet var validatePasswordTxtFld: UITextField!
    @IBOutlet var validatePhoneTxtFld: UITextField!
    @IBAction func validateBtn(_ sender: Any) {
        guard let name = validateNameTxtFld.text,
              let email = validateEmailTxtFld.text,
              let password = validatePasswordTxtFld.text,
              let phone = validatePhoneTxtFld.text else {
            return
        }
        let isValidateName = self.validation.validateName(name: name)
        if (isValidateName == false) {
            print("Incorrect Name")
            return
        }
        let isValidateEmail = self.validation.validateEmailId(emailID: email)
        if (isValidateEmail == false) {
            print("Incorrect Email")
            return
        }
        let isValidatePass = self.validation.validatePassword(password: password)
        if (isValidatePass == false) {
            print("Incorrect Pass")
            return
        }
        let isValidatePhone = self.validation.validaPhoneNumber(phoneNumber: phone)
        if (isValidatePhone == false) {
            print("Incorrect Phone")
            return
        }
        if (isValidateName == true && isValidateEmail == true && isValidatePass == true && isValidatePhone == true) {
            print("All fields are correct")
        }
    }
}

まとめ

バリデーションロジックを汎用クラスに切り出しておくことで、コードの重複を排除でき、正規表現の修正も1箇所で済みます。新しい入力項目が必要になった場合は、validateAnyOtherTextField をひな形として、対応する正規表現を追加するだけで簡単に拡張できます。ぜひ自分のプロジェクトにも取り入れてみてください。

  1. Swiftでナビゲーションバーの境界線を素早く削除する方法

    Swiftでナビゲーションバー(UINavigationBar)の境界線を削除するのはとても簡単で、数行のコードを追加するだけで実現できます。まずは、何も変更せずにアプリを実行したときのナビゲーションバーの見た目を確認してみましょう。ナビゲーションバーの境界線を非表示にする仕組みそれでは、上の画像の下部に表示されている線(境界線・シャドウ)を非表示にしていきます。ナビゲーションバーにデフォルトで表示されるグレーのシャドウと下線は、次の2つの要素によって作られています。背景画像(backgroundImage)シャドウ画像(shadowImage)このうち片方だけでも変化しますが、両方を空の画像

  2. iOSアプリでテキストに影を素早く追加する方法(Swift)

    ゲーム開発や子供向けアプリ、あるいは魅力的なユーザーインターフェースを持つアプリを開発しているなら、テキストに影を追加する方法を知っておくことは非常に重要です。テキストに影をつけることで見た目が美しくなるだけでなく、ユーザーエクスペリエンスの向上にもつながります。 この記事では、UILabelのテキストに影を追加する手順をステップごとに解説します。 手順1:プロジェクトを作成する Xcodeを開き、「New Project」→「Single View Application」を選択して、プロジェクト名を「ShadowText」とします。 手順2:ラベルを配置して接続する Main.storyb