このバグはSwift ver1 がBetaだったときのバグです。現在は発生しません。
Objective-Cで何気なく使っているUIImage
のimageNamed:
メソッド。自分の頭では理解できないことがあったので教えてほしいです。
imageNamed:
メソッド、プロジェクトに入っている画像名を指定してこんな感じ使ってると思います。
UIImage *image = [UIImage imageNamed:@"my_image"];
Swiftだとこんな感じ。
let image:UIImage = UIImage(named:"my_image")
御存じだと思いますが、このimageNamed:
、ファイルが見つからないとnil
を返しますね。
Objective-Cだと、ファイルが見つからなかった場合は**何も表示されません。**ダウンロードしてきた画像は生成できるかnil
チェックすると思うのですが、ローカルの画像はついついnil
チェックを怠ってしまい、画像が表示されていないことに気づかない可能性も出てきます。アプリの規模が大きくなると画像も増えますし困りもんです。
ではSwiftではどうなるか?
まず前提知識として、Swiftはnil
を許容しません。基本的にnil
を扱うことができないんです。
かといって全く扱えないのは困るのでnil
を使いたい場合はOptional型というものにする必要があるのです(OptionalについてはSwiftのOptionalとType Safetyなどを参照してください)。
こんな感じ。ファイルが存在しなくても安全に処理できます。
var imageView: UIImageView
// ?をつけることでOptional型に
let image:UIImage? = UIImage(named:"my_image")
// Optional Bindingでnilチェック
if let validImage = image {
imageView = UIImageView(image: validImage)
} else {
// 画像がなかった場合の処理
}
上記のコードは問題ありません。
次を見てみましょう。
let image:UIImage = UIImage(named:"my_image")
var imageView: UIImageView = UIImageView(image:image)
これで"my_image"
ファイルが存在していなかった場合どうなるか?nil
が返ってきますね。
なぜこんなことを書いているかというとObjective-Cのコードを何も考えずにSwiftに書き直したらこのコードになったからです。
UIImage *image = [UIImage imageNamed:@"my_image"];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
このObjective-Cを、こうSwiftしてしまった。
let image:UIImage = UIImage(named:"my_image")
var imageView: UIImageView = UIImageView(image: image)
で、書き終わった段階で存在しない"my_image"
からインスタンス化しようとする、つまりnil
が返ってきて落ちるだろうということに気がついてXcode6(Beta4)で実行してみたところ。。。
**何もエラーが出ない。**しかもimage
インスタンスはnil
。Optionalじゃないのに。
println("\(image === nil)") // true
もちろん、これが原因でアプリが落ちるよりも画像が表示されないだけで済む方が良いです。そしてOptionalの存在しないObjective-Cと矛盾は起きない。Optionalを意識せずに書き換えても問題なく動く。
でも、文法的にはimageNamed:
の返り値はOptionalであるべきで、UIImage変数もOptionalにするべきなのではないのだろうかと思ったワケです。
分からない。分かる人がいれば教えてほしい!
##追記(201407/29)
imageViewのimageプロパティはImplicitly Unwrapped Optionalsなので、nilが代入