iOS14.~で発生するUITextFieldの入力バグに関して
こんにちは。@torishima__です。
今回は業務で遭遇したUITextFieldの入力時に発生するバグに関して、いろいろ調査して
ある程度原因と対策がわかったので、共有できればと思います。
どんな現象が起きるのか
まずはバグが再現する環境を作ってみました。
- ある画面にtextFieldが複数ある
- それぞれのtextFieldは同じ画面に存在し、textFieldが配置されている感覚も 20pt~40ptくらいでそこまで狭すぎない
- 複数配置されているtextFieldの中に一つだけ password入力をするものが存在している
- password入力用のtextFieldには
isSecureTextEntry
をtrue
にしてある - そのtextFieldが配置されているView、(ViewController)のclassNameがLoginや、SignIn, Accountなどのある程度何をするのかがわかるような名前であること(私の場合は
AccountRegisterViewController
という名前で発生した)
検証に使ったCode
// クラスの名前を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
}
}
今までは(iOS13まで)
textFieldのisSecureTextEntry
を true
にしていると、日本語入力ができない
(フリック入力するキーボードが選択できなくなる)ので qwerty
のキーボードのみでの入力できるようになっておりましたが、
今回発生したバグは、ここの部分でフリック入力ができるキーボードが選択できてしまい、かつフリック入力をしようとしても、
画像の赤枠の文字が打てない現象が起きてしまいます
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や記事でいろいろ見つけて確認した形になります。
以下引用ツイート
どれだけの環境で有効かわからんけど、会社メンバーで検証やってたら変なワークアラウンドを発見した。下記2点。
— takishima / Futurize (@takishimaa_) January 19, 2021
1. そのViewControllerに会員登録っぽいクラス名を使わない。
2. isSecureTextEntryのテキストフィールドを2つ並べない。並べる場合はダミーのTextFieldを間にいれる
iOS 14.2 で isSecureTextEntry を true にしていても英語キーボードにならないバグ?がある。iOS 14.1 までは日本語キーボードを選んでいても isSecureTextEntry な UITextField は英語に強制されていた。
— Yoshizu / S2 Factory (@n0442) November 9, 2020
textContentTypeをpasswordかnewPasswordにしてみてください
— あきお@青髪iOSエンジニア (@akio0911) December 10, 2020
iOS 14.2 で .emailAddress な TextField と isSecureTextEntry = true な TextField を2個並べると .emailAddress な TextField にフォーカス当てた後に isSecureTextEntry = true な TextField にフォーカスあてるとキーボードがバグるのでお気をつけ下さい
— k.yamamoto🐈 (@kymmt24) November 17, 2020
上記のツイートでもあるように、いろいろ考えれば何かしらの対応はできそうだと感じました!
まとめ
今回のバグはOSによるバグみたいですが、クラス名を変えただけで現状が起きなくなってしまったのでなんともな〜という感じですが、なぜクラス名を変えただけでこのようなことが起きるのか追って調査してみようと思います。
(ビルドしたときに何かしら見ているのか?クラス名である程度推測しているのか?知っている方いらしたら教えていただきたいです。)
上記のバグで何かわかったことや、他にもこんなのあるよってのがあればいろいろ議論できてら良いと思ってます。
このバグに限らずですが、OSのバグだから直さなくても良いや、ではなく、なぜこうなるのか、発生させない方法はあるのかなど常日頃考えて行くことが大事なんだと改めて実感いたしました。
今回は読んでいただきありがとうございました。
コメントどしどし待ってます。
追記(2021/2/16)
上記のVCの名前を変更する方法でも治らない現象が起きたため、
対象のTextFieldの並び替えを実施したところ現象が解決いたしました。
対応によっては上記の並び替えや、画面の作り替え等でも解消することがわかりました。
また何かわかったら更新していきます。