概要
つい最近までObjective-CでiOSアプリを作っていた筆者が,Swift移行を進めた際に,最も頭を悩ませたのがOptionalの扱い。もちろん,?や!やif let, guard letは理解できるけども,ベストな方法がなかなか決まらなかった。以下,現状で筆者が思うベストな使い方をまとめておきます。
改善提案や「こんな場合はどうするの?」は大歓迎です。
!がついている変数はいつ使う?
例えば,UIViewControllerのサブクラスでは,よく以下のような定義をしますね。
@IBoutlet weak var titleLabel:UILabel!
Storyboardを使用する際の定番の実装です。これの意味をよく考えてみると,!のついた変数宣言をいつ使うのかが理解できます。
前提として,!のついた変数はOptional型であり,nilを許容します。それがなぜ,Outletの宣言に使われるのか。それは,ViewControllerのインスタンス化とStoryboardの読み込みタイミングが関係しています。
ViewControllerがインスタンス化された時には,まだStoryboardは読み込まれていないわけですね。その時点でViewControllerのtitleLabelはnilになってしまうので,titleLabelはnilを許容しなければなりません。
ただし,一度Storyboardが読み込まれ,titleLabelにUILabelのインスタンスがセットされた後は,このプロパティが変更されることは(ほぼ)ありません。こういう場合に!つきの変数宣言を使用します。最初はnilだが,一度値をセットしたら2度と変更しないようなものは!付きで宣言するということですね。
?がついている変数,何もついていない変数の宣言
!付きの変数についてはわかったけども,?や何もついていない変数についてはどうするべきか。
例えば,何らかの処理が進行中かどうかを示すフラグは,通常Boolで宣言します。
var isProcessing = false
この種の変数はnilは入らないので,宣言と同時に値を代入します。!や?はつきません。
逆に,nilをうまく使う場合としては,例えば何らかのSNS的なアプリで,ユーザーが自分のプロフィール画像を選択するケース。画像の選択はUIImagePickerControllerで良いと思いますが,そこから受け取った画像をどうするか。
var selectedImage:UIImage? = nil
このように選択された画像を保持しておくプロパティを宣言しておき,ユーザーが画像を選択した場合には,その画像をこのプロパティにセットします。
何も選択されていない場合にはnilになっているので,if let...でnilチェックし,nilじゃない場合にはプロフィール画像を更新するわけですね。
if let... はいつ使う? Dictionaryからデータを取り出す場合
ご存知の通り,!や?つきの変数にnilが入っていないかを判定するために使われるのが,if letやguard letです。文法的な定義は他の記事を参考していただくとして,問題はこれらの上手な使い方です。
例えば,JSONでサーバから受け取ったデータ。dictionaryなのだが,[String:Any]だとする。何らかのキーで辞書から値を取り出した場合,値がnilの場合もあるし,nilじゃなかった場合でもStringやIntにキャストしなきゃいけない。キャストが失敗することもある。こういう場合,if let...とas?を使用した書き方がベストプラクティスになるでしょう(自信なし)。
let dict:[String:Any] = ["key_string":"string", "key_int":10]
if let string = dict["key_string"] as? String{
print("stringありまっせ")
}
else{
print("値がなかった場合のデフォルト値が必要なら,ここで決めましょう")
}
as? は,キャストが失敗した場合nilを返します。ここでas!を使ってしまうと,キャストが失敗するとアプリはクラッシュ。as? とif let...を使って値を安全に取り出すわけですね。
guard let ... elseは,いつ使う?
これも文法的な定義は他に譲るとして,この構文の重要な特徴としてあげられるのが,else句では必ずreturnしなきゃいけないということ。つまり,この構文の意味としては「値がnilだったらそこで処理を中断」ということです。
かつてObjective-Cの時代にも「値がnilだったらそこでreturn」というコードはよく書かれていたのだけども,guard let...はまさにそれですね。特にここでサンプルは挙げませんが,guard let...はそういうものだと思います。(自信なし)
最後に
他にもOptionalの扱いに迷うケースがありましたら,ぜひコメントお寄せください。間違いの指摘も歓迎です。