SwiftValidator
ルールベースのSwiftバリデーションライブラリ。UITextField統合で簡単にフォーム検証。
GitHub概要
SwiftValidatorCommunity/SwiftValidator
A rule-based validation library for Swift
スター1,441
ウォッチ39
フォーク373
作成日:2014年11月20日
言語:Swift
ライセンス:MIT License
トピックス
なし
スター履歴
データ取得日時: 2025/10/22 09:50
SwiftValidator
SwiftValidatorは、Swiftで書かれたルールベースのバリデーションライブラリです。UITextFieldとの統合により、iOSアプリケーションのフォーム検証を簡単に実装できます。
特徴
- ルールベースアーキテクチャ: 複数のバリデーションルールを組み合わせて使用
- UITextField統合: UITextFieldを直接バリデータに登録
- カスタマイズ可能: 独自のバリデーションルールを作成可能
- エラーラベル対応: UILabelを使ったエラーメッセージ表示
- 順次評価: ルールを左から右に順番に評価
- 軽量設計: iOSアプリケーションに最適化
インストール
CocoaPods
# Podfile
pod 'SwiftValidator', :git => 'https://github.com/SwiftValidatorCommunity/SwiftValidator.git'
Swift Package Manager
// Package.swift
dependencies: [
.package(url: "https://github.com/SwiftValidatorCommunity/SwiftValidator.git", from: "4.2.0")
]
Carthage
github "SwiftValidatorCommunity/SwiftValidator"
基本的な使用方法
1. Validatorの初期化とフィールド登録
import SwiftValidator
class ViewController: UIViewController, ValidationDelegate {
@IBOutlet weak var emailTextField: UITextField!
@IBOutlet weak var emailErrorLabel: UILabel!
@IBOutlet weak var passwordTextField: UITextField!
@IBOutlet weak var passwordErrorLabel: UILabel!
@IBOutlet weak var confirmPasswordTextField: UITextField!
@IBOutlet weak var confirmPasswordErrorLabel: UILabel!
let validator = Validator()
override func viewDidLoad() {
super.viewDidLoad()
// フィールドをバリデータに登録
validator.registerField(emailTextField,
errorLabel: emailErrorLabel,
rules: [RequiredRule(), EmailRule()])
validator.registerField(passwordTextField,
errorLabel: passwordErrorLabel,
rules: [RequiredRule(), MinLengthRule(length: 8)])
validator.registerField(confirmPasswordTextField,
errorLabel: confirmPasswordErrorLabel,
rules: [RequiredRule(), ConfirmationRule(confirmField: passwordTextField)])
}
@IBAction func submitButtonTapped(_ sender: UIButton) {
validator.validate(self)
}
}
2. ValidationDelegateの実装
extension ViewController: ValidationDelegate {
func validationSuccessful() {
// バリデーション成功時の処理
print("フォームのバリデーションが成功しました")
// フォーム送信処理を実装
submitForm()
}
func validationFailed(_ errors: [(Validatable, ValidationError)]) {
// バリデーション失敗時の処理
for (field, error) in errors {
print("バリデーションエラー: \(error.errorMessage)")
// エラーラベルの表示やフィールドのハイライトなど
}
}
}
組み込みバリデーションルール
基本ルール
// 必須フィールド
RequiredRule(message: "この項目は必須です")
// 最小文字数
MinLengthRule(length: 8, message: "8文字以上で入力してください")
// 最大文字数
MaxLengthRule(length: 50, message: "50文字以下で入力してください")
// 正確な文字数
ExactLengthRule(length: 10, message: "10文字で入力してください")
専用ルール
// メールアドレス
EmailRule(message: "正しいメールアドレスを入力してください")
// フルネーム
FullNameRule(message: "フルネームを入力してください")
// 郵便番号
ZipCodeRule(message: "正しい郵便番号を入力してください")
// 確認フィールド(パスワード確認など)
ConfirmationRule(confirmField: passwordTextField,
message: "パスワードが一致しません")
正規表現ルール
// カスタム正規表現
RegexRule(regex: "^[0-9]+$", message: "数字のみ入力してください")
// 電話番号
RegexRule(regex: "^\\d{3}-\\d{4}-\\d{4}$",
message: "XXX-XXXX-XXXX の形式で入力してください")
カスタムバリデーションルール
基本的なカスタムルール
class CustomRule: Rule {
private var message: String
init(message: String = "カスタムバリデーションエラー") {
self.message = message
}
func validate(_ value: String) -> Bool {
// カスタムバリデーションロジック
return value.count >= 3 && value.allSatisfy { $0.isLetter }
}
func errorMessage() -> String {
return message
}
}
RegexRuleを継承したカスタムルール
class SSNRule: RegexRule {
static let regex = "^\\d{3}-\\d{2}-\\d{4}$"
convenience init(message: String = "正しいSSN形式で入力してください") {
self.init(regex: SSNRule.regex, message: message)
}
}
class JapanesePhoneRule: RegexRule {
static let regex = "^(070|080|090)-\\d{4}-\\d{4}$"
convenience init(message: String = "正しい日本の携帯電話番号を入力してください") {
self.init(regex: JapanesePhoneRule.regex, message: message)
}
}
高度な使用方法
個別フィールドバリデーション
// 特定のフィールドのみをバリデーション
validator.validateField(emailTextField) { [weak self] error in
if let error = error {
self?.handleValidationError(error)
} else {
self?.handleValidationSuccess()
}
}
フィールドの動的登録解除
// フィールドの登録解除
validator.unregisterField(emailTextField)
// 条件に応じて再登録
if shouldValidateEmail {
validator.registerField(emailTextField,
errorLabel: emailErrorLabel,
rules: [RequiredRule(), EmailRule()])
}
エラーハンドリングとUI更新
func validationFailed(_ errors: [(Validatable, ValidationError)]) {
// すべてのエラーラベルをクリア
clearAllErrorLabels()
// エラーを個別に処理
for (field, error) in errors {
if let textField = field as? UITextField {
// テキストフィールドの境界線を赤色に
textField.layer.borderColor = UIColor.red.cgColor
textField.layer.borderWidth = 1.0
// エラーラベルに対応
if let errorLabel = getErrorLabel(for: textField) {
errorLabel.text = error.errorMessage
errorLabel.isHidden = false
}
}
}
}
func validationSuccessful() {
// すべてのエラー表示をクリア
clearAllErrorLabels()
// 成功時のスタイル適用
applySuccessStyle()
}
実践的なフォームバリデーション例
ユーザー登録フォーム
class SignUpViewController: UIViewController, ValidationDelegate {
@IBOutlet weak var usernameTextField: UITextField!
@IBOutlet weak var emailTextField: UITextField!
@IBOutlet weak var passwordTextField: UITextField!
@IBOutlet weak var confirmPasswordTextField: UITextField!
@IBOutlet weak var phoneTextField: UITextField!
@IBOutlet weak var ageTextField: UITextField!
// エラーラベル
@IBOutlet weak var usernameErrorLabel: UILabel!
@IBOutlet weak var emailErrorLabel: UILabel!
@IBOutlet weak var passwordErrorLabel: UILabel!
@IBOutlet weak var confirmPasswordErrorLabel: UILabel!
@IBOutlet weak var phoneErrorLabel: UILabel!
@IBOutlet weak var ageErrorLabel: UILabel!
let validator = Validator()
override func viewDidLoad() {
super.viewDidLoad()
setupValidation()
}
private func setupValidation() {
// ユーザー名: 必須、3-20文字、英数字のみ
validator.registerField(usernameTextField,
errorLabel: usernameErrorLabel,
rules: [
RequiredRule(message: "ユーザー名は必須です"),
MinLengthRule(length: 3, message: "ユーザー名は3文字以上で入力してください"),
MaxLengthRule(length: 20, message: "ユーザー名は20文字以下で入力してください"),
RegexRule(regex: "^[a-zA-Z0-9]+$", message: "ユーザー名は英数字のみ使用できます")
])
// メールアドレス: 必須、有効なメール形式
validator.registerField(emailTextField,
errorLabel: emailErrorLabel,
rules: [
RequiredRule(message: "メールアドレスは必須です"),
EmailRule(message: "正しいメールアドレスを入力してください")
])
// パスワード: 必須、8文字以上、英数字記号混在
validator.registerField(passwordTextField,
errorLabel: passwordErrorLabel,
rules: [
RequiredRule(message: "パスワードは必須です"),
MinLengthRule(length: 8, message: "パスワードは8文字以上で入力してください"),
RegexRule(regex: "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]+$",
message: "パスワードは大文字、小文字、数字、記号を含んでください")
])
// パスワード確認: 必須、パスワードと一致
validator.registerField(confirmPasswordTextField,
errorLabel: confirmPasswordErrorLabel,
rules: [
RequiredRule(message: "パスワード確認は必須です"),
ConfirmationRule(confirmField: passwordTextField,
message: "パスワードが一致しません")
])
// 電話番号: 必須、日本の携帯電話番号形式
validator.registerField(phoneTextField,
errorLabel: phoneErrorLabel,
rules: [
RequiredRule(message: "電話番号は必須です"),
JapanesePhoneRule(message: "正しい日本の携帯電話番号を入力してください(例: 090-1234-5678)")
])
// 年齢: 必須、18歳以上120歳以下
validator.registerField(ageTextField,
errorLabel: ageErrorLabel,
rules: [
RequiredRule(message: "年齢は必須です"),
AgeRule(message: "年齢は18歳以上120歳以下で入力してください")
])
}
@IBAction func signUpButtonTapped(_ sender: UIButton) {
validator.validate(self)
}
// MARK: - ValidationDelegate
func validationSuccessful() {
// バリデーション成功時の処理
showSuccessMessage()
performSignUp()
}
func validationFailed(_ errors: [(Validatable, ValidationError)]) {
// バリデーション失敗時の処理
showValidationErrors(errors)
}
}
// カスタム年齢バリデーションルール
class AgeRule: Rule {
private var message: String
init(message: String = "年齢は18歳以上120歳以下で入力してください") {
self.message = message
}
func validate(_ value: String) -> Bool {
guard let age = Int(value) else { return false }
return age >= 18 && age <= 120
}
func errorMessage() -> String {
return message
}
}
リアルタイムバリデーション
extension SignUpViewController: UITextFieldDelegate {
func textFieldDidEndEditing(_ textField: UITextField) {
// フォーカスが外れた時にそのフィールドをバリデーション
validator.validateField(textField) { [weak self] error in
DispatchQueue.main.async {
if let error = error {
self?.showFieldError(textField, error: error)
} else {
self?.clearFieldError(textField)
}
}
}
}
private func showFieldError(_ textField: UITextField, error: ValidationError) {
// エラー表示ロジック
textField.layer.borderColor = UIColor.red.cgColor
textField.layer.borderWidth = 1.0
if let errorLabel = getErrorLabel(for: textField) {
errorLabel.text = error.errorMessage
errorLabel.isHidden = false
}
}
private func clearFieldError(_ textField: UITextField) {
// エラークリアロジック
textField.layer.borderColor = UIColor.systemGray4.cgColor
textField.layer.borderWidth = 1.0
if let errorLabel = getErrorLabel(for: textField) {
errorLabel.isHidden = true
}
}
}
テスト
import XCTest
@testable import YourApp
import SwiftValidator
class ValidationTests: XCTestCase {
var validator: Validator!
var testTextField: UITextField!
override func setUp() {
super.setUp()
validator = Validator()
testTextField = UITextField()
}
func testEmailValidation() {
validator.registerField(testTextField,
rules: [RequiredRule(), EmailRule()])
// 有効なメールアドレス
testTextField.text = "[email protected]"
let expectation = self.expectation(description: "Validation completed")
validator.validateField(testTextField) { error in
XCTAssertNil(error, "有効なメールアドレスでエラーが発生しました")
expectation.fulfill()
}
wait(for: [expectation], timeout: 1.0)
}
func testInvalidEmailValidation() {
validator.registerField(testTextField,
rules: [RequiredRule(), EmailRule()])
// 無効なメールアドレス
testTextField.text = "invalid-email"
let expectation = self.expectation(description: "Validation completed")
validator.validateField(testTextField) { error in
XCTAssertNotNil(error, "無効なメールアドレスでエラーが発生しませんでした")
expectation.fulfill()
}
wait(for: [expectation], timeout: 1.0)
}
func testCustomRule() {
let customRule = AgeRule()
validator.registerField(testTextField, rules: [customRule])
// 有効な年齢
testTextField.text = "25"
let expectation = self.expectation(description: "Validation completed")
validator.validateField(testTextField) { error in
XCTAssertNil(error, "有効な年齢でエラーが発生しました")
expectation.fulfill()
}
wait(for: [expectation], timeout: 1.0)
}
}
ベストプラクティス
1. エラーメッセージの国際化
// Localizable.strings
"validation.required" = "この項目は必須です";
"validation.email" = "正しいメールアドレスを入力してください";
"validation.minLength" = "最低%d文字で入力してください";
// 使用例
RequiredRule(message: NSLocalizedString("validation.required", comment: ""))
EmailRule(message: NSLocalizedString("validation.email", comment: ""))
2. パフォーマンスの最適化
// 重いバリデーションは非同期で実行
class AsyncValidationRule: Rule {
func validate(_ value: String) -> Bool {
// 重い処理は別スレッドで実行
return true
}
}
3. アクセシビリティ対応
// エラーラベルにアクセシビリティ情報を追加
errorLabel.accessibilityLabel = "エラーメッセージ"
errorLabel.accessibilityTraits = .staticText
// テキストフィールドとエラーラベルを関連付け
textField.accessibilityDescribedBy = errorLabel
まとめ
SwiftValidatorは、iOSアプリケーションのフォームバリデーションを簡単かつ効率的に実装できる優れたライブラリです。ルールベースのアーキテクチャにより、複雑なバリデーションロジックも分かりやすく管理できます。
主な利点
- シンプルなAPI: 直感的で使いやすいインターフェース
- 拡張性: カスタムルールの作成が容易
- UIKitとの統合: UITextFieldとの自然な統合
- エラーハンドリング: 詳細なエラー情報とUI更新
- テスト可能性: ユニットテストの作成が容易
SwiftValidatorを使用することで、堅牢で使いやすいフォームバリデーション機能をiOSアプリケーションに簡単に追加できます。