Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
5
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

updated at

UITextFieldの空文字""とnil

きっかけ

練習でサンプルアプリを作っていて、その中で
「TextFieldに何も文字が入力されていない状態でボタンを押した場合アラートを出す」という実装をしようと思いました。
今までTextFieldに何も入力されていないということを表現するために何となく空文字""を使っていましたが、ふと nilじゃいけないのか...?🤔と疑問に思ったので色々試してみた結果、学んだことがあったので記しておきます。
その時に書いたコードが以下のものです。

ViewController

 @IBOutlet private weak var textField: UITextField!
 @IBOutlet private weak var label: UILabel!

 override func viewDidLoad() {
     super.viewDidLoad()
 }

 @IBAction func print(_ sender: Any) {
     guard textField.text != "" else {
     alert(message: "未入力です")
     return
     }
     label.text = textField.text
     view.endEditing(true)
 }

 private func alert(message: String) {
     let alertController = UIAlertController(title: "エラー",message: message, preferredStyle: .alert)
     let action = UIAlertAction(title: "OK", style: .default, handler: nil)
     alertController.addAction(action)
     present(alertController, animated: true, completion: nil)
 }

TextFieldに何も入力されていないままprintボタンを押すとこんな感じでアラートが出ます。
Simulator Screen Shot - iPhone 11 - 2020-08-14 at 00.56.20.png

疑問

要するに何も入力されてなければalertを表示させたいわけですが、

guard textField.text != ""

のところを

guard textField.text != nil

とやっちゃいかんのか?と思い、nilに変えて実行してみたところ、guard文をすり抜けてしまいalertが表示されませんでした。
textField.textの型はString?型でオプショナルなので、nilが入る余地があり、未入力ということは値が入っていないnilってことなのに何でguard文をすり抜けるんだろう?と疑問に思いました。

なぜなのか

まず、「なぜnilを入れた時にguard文をすり抜けてしまうのか」についてですが、これはTextFieldの初期値が""で設定されているからだそうで、そのため初期状態が""の状態でprintボタンを押しても「nilではない」と判定されてしまうため、guard文をすり抜けてしまうわけです。

えっ、じゃあTextField.textにnilって絶対入らなくない?と思いPlaygroundで色々試してみた結果、以下のようになりました。
スクリーンショット 2020-08-14 1.22.27.png
これを見る限りUITextFieldの初期値は空文字""で、後からnilを代入しても空文字""扱いとなるそうです。
ついでにUILabelでも試してみたところ、こちらはnilを代入したところちゃんとnilが入ってました(当たり前)。

じゃあTextFieldにnilが入らないってことはアンラップしないで使っていいの?

TextFieldにnilが入る場合が存在しないってことはわざわざアンラップしなくてもいいのか?
(現に僕もナチュラルにguard textField.text != "" elseとアンラップしないで書いていた)
と思い現役のエンジニアさんに質問させていただいたところ、
「型がOptionalなら、将来的に挙動が変わってnilが返ってくることもありえるので、現在挙動としてnilがありえなかったとしても、型がOptionalの場合はnilを考慮しないといけない」とのことでした。
ちゃんとしたやり方?で書くとなると以下のように書くのが良いそうです。

guard !(textField.text ?? "").isEmpty else { ... } 

やはりオプショナル型はしっかりアンラップを行い、String?型をString型にした上でisEmptyプロパティにアクセスし空欄かどうかチェックする、というのが定石だそうです。

まとめ

オプショナル型を適当に扱いがちっていうのは初心者にあるあるだと思うので、今回の気付きはとても勉強になりました。
「必ず将来長期に渡ってその値はnilになり得ないのか」ということをしっかり意識してコードを書いていきたいです(小並感)。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
5
Help us understand the problem. What are the problem?