【Swift】複数のUITextFieldで文字数制限する方法

# 完成イメージ
![demo_qiita_maxLength.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480691/47a9250d-8aa6-add8-1334-6d31f2a0c8e1.gif)
`名前は4文字`、`趣味は8文字`で入力制限をしています。

## 動作環境
Xcode10.2.1、Swift5.0.1

## UITextFieldのTagを設定
<img width="1400" alt="スクリーンショット 2019-09-29 20.11.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480691/d15b90b9-c9d2-0a2c-0cd1-e1578710f1b2.png">
今回は複数のUITextFieldを対象とするため、Tagを設定してそれぞれのUTTextFieldを識別します。

Tagの設定方法はUITextFieldを選択し、インスペクターエリアのAttributes Inspectorから設定できます。
・名前　→　Tagを1に設定
・趣味　→　Tagを2に設定
※UTTextFieldの名前やタグの番号は適宜変えてください
 
## textField(_:shouldChangeCharactersIn:replacementString:)で入力制限
```swift
optional func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
```

`textField()`はUITextFieldDelegateのプロトコルに定義されており、textFieldに値が入力される度に呼ばれるメソッドになります。戻り値がtrueの場合は、入力された値をtextFieldに反映し、逆にfalseの場合は反映しません。

それぞれの引数の意味は以下です。
・`textField`: textFieldに既に含まれている値
・`range`: 置換される値の範囲
・`string`: 入力されている値

例えば、textFieldに`123`が入力されており、`4`が入力されたタイミングにtextField()が呼ばれた場合は`textField.text="123"`、`string.text="4"`となります。

Appleの公式ドキュメント
[textField(_:shouldChangeCharactersIn:replacementString:) - UITextFieldDelegate | Apple Developer Documentation](https://developer.apple.com/documentation/uikit/uitextfielddelegate/1619599-textfield)

## Tag毎に入力文字数を制限
`textFieldの文字数とstringの文字数の合計値 =< 最大入力可能数`で戻り値を判断しています。（それぞれのTextFieldは最初に設定したTagで識別しています。）

コードは以下になります。

```swift
    // 文字数制限
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        // 文字数最大値を定義
        var maxLength: Int = 0
        
        switch (textField.tag) {
        case 1: // 名前の文字数
            maxLength = 4
        case 2: // 趣味の文字数
            maxLength = 8
        default:
            break
        }
        // textField内の文字数
        let textFieldNumber = textField.text?.count ?? 0
        // 入力された文字数
        let stringNumber = string.count
        
        return textFieldNumber + stringNumber <= maxLength
    }
```

今回の`textField()`は`UITextFieldDelegate`のプロトコルで定義されているため、以下の実装も必要です。

・Tagを設定したUITextFieldをViewControllerに接続
・UITextFieldDelegateの継承とUITextFieldのDelegateを定義
・キーボードを閉じる処理を追加（こちらはTextFieldを利用するなら必要なので）

上記を含めると全体のコードは以下になります。

```swift:ViewController.swift
import UIKit

class ViewController: UIViewController, UITextFieldDelegate {
    
    // 名前
    @IBOutlet weak var name: UITextField!
    // 趣味
    @IBOutlet weak var hobby: UITextField!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // delegate定義
        name.delegate = self
        hobby.delegate = self
    }
    
    // 文字数制限
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        // 文字数最大値を定義
        var maxLength: Int = 0
        
        switch (textField.tag) {
        case 1: // 名前の文字数
            maxLength = 4
        case 2: // 趣味の文字数
            maxLength = 8
        default:
            break
        }
        // textField内の文字数
        let textFieldNumber = textField.text?.count ?? 0
        // 入力された文字数
        let stringNumber = string.count
        
        return textFieldNumber + stringNumber <= maxLength
    }
    
    // キーボードを閉じる（returnキーを押下時）
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder()
        return true
    }
    
    // キーボードを閉じる（UITextField以外の部分を押下時）
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.view.endEditing(true)
    }
}
```
以上になります。
もし不明点や間違い等があればコメントくださいm(_ _)m