UITextFieldViewのleftViewに隠された仕様について
TL;DR
- 1つのViewインスタンスを、複数の
UITextFieldView
のleftView
に同時に表示することはできない - 同時には表示することができないので、
leftViewMode
を.whileEditing
に指定すれば1つのViewインスタンスを使い回すことも可能 - この辺りの仕様は公式ドキュメントには記載されてないのでツライ
やりたかったこと
UITableViewCell
のsubViewにUITextField
を配置するUITextField
のleftView
にUIImageView
を常に表示するUITextField
のendEditingのコールバックでsuperViewのUITableViewCell
をリロードする
問題
初回表示時は問題なくleftView
が表示されましたが、Cellをリロードした直後にアプリがハングし、以後メモリ使用量が増え続ける問題が発生しました。
仮説1
メモリが増え続けていたことから、まずはメモリリークを疑いました。 XcodeのInstrumentsで調べてみましたが、これといったリーク箇所を見つけることができませんでした。
仮説2
Cellのリロード直後に問題が発生していたことから、再レンダリングされる時にleftView
に指定しているViewのインスタンスが解放されていることを疑いました。
leftView
をstatic変数にするなど試してみましたが解決しませんでした。
デバッグ
UITextField
のleftViewMode
を.always
から.whileEditing
に変更してみたところ、問題が発生しなくなることが判明しました。.unlessEditing
だと依然として問題は発生しました。
以上のことからUITableView
に起因する問題ではなく、UITextField
そのものが起因の問題もしくは仕様なのではないかと考えられます。
検証
UITableView
を利用せず、以下のようなシンプルなサンプルを実装して検証してみました。
class ViewController: UIViewController { @IBOutlet weak var textField_1: UITextField! @IBOutlet weak var textField_2: UITextField! let icon = UIImageView(image: #imageLiteral(resourceName: "any")) override func viewDidLoad() { super.viewDidLoad() self.textField_1.leftView = icon self.textField_1.leftViewMode = .always self.textField_2.leftView = icon self.textField_2.leftViewMode = .always } }
案の定、アプリが動かなくなり、メモリが増え続けます。前述した問題と同じ症状です。どうやらUITextField
に何らかの仕様か問題があることが確定しました。ググりやすくなります。
ググる
https://stackoverflow.com/a/6967456/4834226
A single UIView (or UIImageView) cannot be displayed on screen twice at the same time. I fixed this by creating separate padding views for the UITextFields.
つまり、「1つのUIView(もしくはUIImageView)は同時に2回スクリーン上に表示することはできない」。
公式ドキュメントには書いてないけど・・・。
結論
公式ドキュメントには特に記載がありませんが、1つのView
インスタンスを複数のUITextField.leftView
に同時に表示することはできない、という仕様ということが判明しました。
UITableViewCell
のケースでは、Cellが再利用される(複数のViewに利用される)ことでアプリがハングしていたと考えられます。