今日はStoryboardを使って開発をしているとよく見かけるUIView!
の!
部分について書いていこうと思います。
let view: UIView!
!
とは
!
はImplicitlyUnwrappedOptionalの糖衣構文になります。
// 下の2つは同じ意味
let view1: UIView!
let view2: ImplicitlyUnwrappedOptional<UIView>
?
がOptionalの糖衣構文な事に似ています。
// 下の2つは同じ意味
let view1: UIView?
let view2: Optional<UIView>
ImplicitlyUnwrappedOptionalとは
Optionalと同じでnilを代入する事ができる型です。
Optionalと違ってアンラップせずに使えるというメリットはあるのですが、中にnilが入っていた場合はクラッシュします。
let view: UIView! = nil
print(view.frame) // → アプリが落ちる
ImplicitlyUnwrappedOptional型とOptional型
ImplicitlyUnwrappedOptional型とOptional型があると書いたのですが、そうなるとそれぞれのnilが等しいかが気になります。
実際に確かめたところ、Optional.NoneとImplicitlyUnwrappedOptional.Noneの比較はtrueを返す事が分かりました。
let int1: Int? = nil
let int2: Int! = nil
print(int1 == int2) // true
print(Optional.None == ImplicitlyUnwrappedOptional.None) // true
nil以外の比較は下の結果になりました。
let int1: Int? = 1
let int2: Int! = 1
let int3: Int = 1
print(int1 == int2) // true
print(int1 == int3) // true
print(int2 == int3) // true
ImplicitlyUnwrappedOptionalの使いどころ
ImplicitlyUnwrappedOptionalは普段開発をしていて使う事は少ないです。
自分が使うとしたら下の2つの条件を満たした時かと思います。
- インスタンス変数
- initで初期化できない
- nilが入った場合にはアプリがクラッシュしてほしい
上2つについて説明していきます。
インスタンス変数
ローカル変数ではnilを許可するならOptionalを使えばいいしnilを許容しないなら!
も?
も付かない普通の型として宣言すれば済みます。
その為インスタンス変数以外では使う事はほぼないかと思っています。
一応Optionalを代入できるという長所はあるのですが、Optionalを代入する場合はアンラップした方が安全なのでその辺りは考慮しなくて良い気がしています。
var view1: UIView?
var view2: UIView!
var view3: UIView
view2 = view1 // エラーにならない
view3 = view1 // エラーになる
initで初期化できない
Swiftではinitializerで初期化できるプロパティーには?
や!
を付ける必要がありません。
その為nilを許容したくないインスタンス変数はinitializerで値を入れるだけで済みます。
逆にStoryboardのように裏側で値をセットする場合はinitializerでの値セットが難しいのでImplicitlyUnwrappedOptionalとして宣言する必要が出てきます。
class MyClass {
var prop: Int
init(prop: Int) {
self.prop = prop
}
}
まとめ
今日はImplicitlyUnwrappedOptionalの概要・仕様・使いどころについて書いてきました。
ImplicitlyUnwrappedOptionalは「初期化時に値を入れずにnilが入らない事を明示的に示せる」という事でしっかり使えば堅牢なアプリケーションを使えそうな気がしています。
とは言えImplicitlyUnwrappedOptionalを使うかどうかの基準をチーム内で共有する事は大変そうですし、アプリがクラッシュするのは痛いので基本的に使わない方が安全な気がしています。