iOS14.~ で発生するUITextFieldの入力バグに関しての調査

# iOS14.~で発生するUITextFieldの入力バグに関して

こんにちは。@torishima__です。
今回は業務で遭遇したUITextFieldの入力時に発生するバグに関して、いろいろ調査して
ある程度原因と対策がわかったので、共有できればと思います。

## どんな現象が起きるのか
まずはバグが再現する環境を作ってみました。

 
- ある画面にtextFieldが複数ある
- それぞれのtextFieldは同じ画面に存在し、textFieldが配置されている感覚も 20pt~40ptくらいでそこまで狭すぎない
- 複数配置されているtextFieldの中に一つだけ password入力をするものが存在している
- password入力用のtextFieldには`isSecureTextEntry` を `true`にしてある
- そのtextFieldが配置されているView、（ViewController）のclassNameがLoginや、SignIn, Accountなどのある程度何をするのかがわかるような名前であること（私の場合は `AccountRegisterViewController`という名前で発生した）

#### 検証に使ったCode
```swift
// クラスの名前をViewContoroller　→　AccountRegisterViewControllerに変えると発生する
// AccountRegisterViewController　→　ViewControllerに戻すとバグが解消される
class AccountRegisterViewController: UIViewController, UITextFieldDelegate {
    @IBOutlet weak var textField1: UITextField!
    @IBOutlet weak var textField2: UITextField! // password
    @IBOutlet weak var textField3: UITextField!
    @IBOutlet weak var textField4: UITextField!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        textField1.delegate = self
        textField2.delegate = self
        textField3.delegate = self
        textField4.delegate = self
        setupTextField()
    }
    
    func setupTextField() {
        textField1.keyboardType = .asciiCapable
        // password用の設定
        textField2.keyboardType = .asciiCapable
        textField2.textContentType = .password
        textField2.isSecureTextEntry = true

        textField3.keyboardType = .asciiCapable
        textField4.keyboardType = .asciiCapable
    }
    
    // Nextを押すと自動で次のキーボードに切り替え
    // 検証のため無限にNextできるようにしてある
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        if (textField == textField1) {
            textField2?.becomeFirstResponder()
        } else if (textField == textField2) {
            textField3?.becomeFirstResponder()
        } else if (textField == textField3) {
            textField4?.becomeFirstResponder()
        } else if (textField == textField4) {
            textField1?.becomeFirstResponder()
        }
        return true
    }

}

```


<img width="330" src="https://user-images.githubusercontent.com/52149750/107869113-fdc79a80-6ecd-11eb-8b20-ac174e2b945a.png">
よくあるLogin画面とか、アカウント登録画面とか上記のような画面構成になっていると思います。

 ---
今までは(iOS13まで)
textFieldの`isSecureTextEntry` を `true`にしていると、日本語入力ができない
（フリック入力するキーボードが選択できなくなる）ので `qwerty`のキーボードのみでの入力できるようになっておりましたが、
今回発生したバグは、ここの部分でフリック入力ができるキーボードが選択できてしまい、かつフリック入力をしようとしても、
画像の赤枠の文字が打てない現象が起きてしまいます
<img width="330" src="https://user-images.githubusercontent.com/52149750/107869160-4e3ef800-6ece-11eb-8ca7-7157a774af99.png">

`qwertyキーボード `に切り替えてしまえば、そのフリック入力ができるキーボードが出てこなくなり、通常通り入力ができるようになります。


## 先に結論
業務が忙しくて結論だけ知りたいって人はこちらをみてください。
https://developer.apple.com/forums/thread/668859
 >In my case, Everything is fine in LoginViewController, but in SignUpViewController, this issue happened
I solved it by rename SignUpViewController to SUpViewController. A magic!!! I don't know why it works

magic!!!!

 私も上記の対応で、 ViewControllerの名前を変更したところ上記のバグが発生しなくなりました。
上記はぜひサンプル等作って確認してみてください。

 - 他の解決策はあるのか？
    - TextFieldの扱う場合、何を入力するのか、どの画面でUserに入力させるのかをちゃんと考えて実装してあげる必要があること
    - SecureTextEntryのようなpasswordを隠す機能を自前で実装する
    - TextFieldの並び順を考慮して実装する

## 私が実施してみたこと
さてここからは実際に私が調査した中で、いろいろ試したこと書きます。
こちらのバグの現象でググると、結構起きている人はいるみたいですが、なかなかこれだという情報がなく最終的にClass名を変えて実装したところバグは解消されました。

##### 以下私が全てやったこと
- 全てのTextFieldに keyboardTypeを設定した
- password入力するTextFieldのtextContentTypeを`.newPassword`を設定した
- TextFieldの並び順を変えてみた
- 各TextFieldの並びの感覚を広くとってみた(50ptほど)

上記のことはTwitterや記事でいろいろ見つけて確認した形になります。

以下引用ツイート

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">どれだけの環境で有効かわからんけど、会社メンバーで検証やってたら変なワークアラウンドを発見した。下記2点。<br><br>1. そのViewControllerに会員登録っぽいクラス名を使わない。<br>2. isSecureTextEntryのテキストフィールドを2つ並べない。並べる場合はダミーのTextFieldを間にいれる</p>&mdash; takishima / Futurize (@takishimaa_) <a href="https://twitter.com/takishimaa_/status/1351525357229260801?ref_src=twsrc%5Etfw">January 19, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">iOS 14.2 で isSecureTextEntry を true にしていても英語キーボードにならないバグ？がある。iOS 14.1 までは日本語キーボードを選んでいても isSecureTextEntry な UITextField は英語に強制されていた。</p>&mdash; Yoshizu / S2 Factory (@n0442) <a href="https://twitter.com/n0442/status/1325756118832873472?ref_src=twsrc%5Etfw">November 9, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">textContentTypeをpasswordかnewPasswordにしてみてください</p>&mdash; あきお＠青髪iOSエンジニア (@akio0911) <a href="https://twitter.com/akio0911/status/1336873572837429248?ref_src=twsrc%5Etfw">December 10, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">iOS 14.2 で .emailAddress な TextField と isSecureTextEntry = true な TextField を2個並べると .emailAddress な TextField にフォーカス当てた後に isSecureTextEntry = true な TextField にフォーカスあてるとキーボードがバグるのでお気をつけ下さい</p>&mdash; k.yamamoto🐈 (@kymmt24) <a href="https://twitter.com/kymmt24/status/1328588533381140484?ref_src=twsrc%5Etfw">November 17, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

上記のツイートでもあるように、いろいろ考えれば何かしらの対応はできそうだと感じました！


## まとめ
今回のバグはOSによるバグみたいですが、クラス名を変えただけで現状が起きなくなってしまったのでなんともな〜という感じですが、なぜクラス名を変えただけでこのようなことが起きるのか追って調査してみようと思います。

（ビルドしたときに何かしら見ているのか？クラス名である程度推測しているのか？知っている方いらしたら教えていただきたいです。）

上記のバグで何かわかったことや、他にもこんなのあるよってのがあればいろいろ議論できてら良いと思ってます。
このバグに限らずですが、OSのバグだから直さなくても良いや、ではなく、なぜこうなるのか、発生させない方法はあるのかなど常日頃考えて行くことが大事なんだと改めて実感いたしました。

今回は読んでいただきありがとうございました。
コメントどしどし待ってます。


## 追記（2021/2/16)
上記のVCの名前を変更する方法でも治らない現象が起きたため、
対象のTextFieldの並び替えを実施したところ現象が解決いたしました。
対応によっては上記の並び替えや、画面の作り替え等でも解消することがわかりました。

また何かわかったら更新していきます。