- 宣言、ダウンキャスト、メソッド呼出、メソッド引数、左辺値、5つのケースでメモを残しておく。(Xcode7 beta1 + Swift2.0)
- 宣言
var x:Int! = 1
var y:Int? = 2
print(x)
print(y)
//1
//Optional(2)
//x = nil
//y = nil
var z: Int = 3
//z = nil // compile error as below
//error: cannot assign a value of type 'nil' to a value of type 'Int'
//1)x is an Optional(nil acceptable), but already unwrapped
//2)y is also an Optional(nil acceptable), but wrapped(Optional 2)
// so method call such as y!.distanceTo(-2) needs "!" notation.
print(y!.distanceTo(-2))
print(x.distanceTo(-2))
print(x!.distanceTo(-2))
//print(z!.distanceTo(-2)) //
//error: operand of postfix '!' should have optional type; type is 'Int'
//3) z is not nil acceptable.
- ポイント
- 記号!, ?何れかを使って宣言すれば、Optional(nil acceptable)と見なされる。
- Optional型には2つのstateがあって、一つはwrappedで、もう一つはunwrapped。
- 記号の有無は、メソッド呼出時に影響でる。メソッド呼出時にwrappedなインスタンスであれば記号!を使ってメソッド呼出が必要。Optional型であってもunwrappedなら記号!不要でメソッド呼出可能。
- Optional型で無いインスタンスに記号!を付けてメソッド呼出を行えば、コンパイルエラー発生。(例:上記のvar z)
- Optional型であっても既にunwrappedな上記のvar xであれば記号!無しにメソッド呼出可能。(ex: print(x.distanceTo(-2)))記号!があってもOK。(ex: print(x!.distanceTo(-2)))
- ダウンキャスト
let delegateObj = anObject as! AppDelegate // (1)
//let delegateObj = anObject as? AppDelegate // (2)
let delegateObj = anObject as AppDelegate! // (3)
- ポイント
- anObject変数のnil check無でnon-opptional型へ強制ダウンキャスト 【場合(1)】する。anObjectがnilならエラー発生する。
- anObject変数のnil check有りでnon-opptional型へ強制ダウンキャスト 【場合(2)】、ただしキャストに失敗してもエラー発生させない。(swift2.0ではコンパイルエラー)check失敗でも。。。というよりコンパイルエラー発生。
- opptional型へダウンキャスト 【場合(3)】、ただし、unwrap済。
- asキーワード(?, !も付かないas)はキャストアップへ使う。例えば、UITouchからNSObjectへのキャストへ使うが、あまり使い道が無い。
- メソッド呼出
foo!.goToSchool() // (1)
foo?.goToSchool() // (2)
- ポイント
- nil checkせずにfooインスタンスのメソッド呼出をする。check失敗時、nilに対しgoToSchool()メソッド呼出をするので、実行時にエラーが発生する。nil guardが必要。
- nil checkしてからfooインスタンスのメソッド呼出する。check失敗時、メソッド呼出しない。fooがnilでも実行時にエラー発生しない。
- メソッド引数
宣言の時と同じ。
- 左辺値
self.canvas1 = self.canvasImage1()
// self.canvas1! = self.canvasImage1() nil found error occured.
// self.canvas1? = self.canvasImage1() blank is drawn.
- ポイント
- 左辺値に用いて値代入する際には、unwrap済みである事一見で判る!?記号が無い状態で記述しないと、実行時にエラーとなるか、nil代入されちゃう。
!記号付きで左辺値に記述すると、nil checkせずunwrapする。unwrapの結果nilなら定数nilへの代入は出来ないのでnil found実行時エラーが発生。unwrapの結果nilでないなら、変数の中身が上書きされる。
?記号付きで左辺値を記述すると、nil checkをしてからunwrapする。check失敗すると代入は実行されない。check成功するとunwrapされた変数の中身は右辺値で上書きされる。
check失敗時、実行時エラーも発生せず、上記の例であればblankスクリーンが表示される。なお、canvasはUIImage型のオフスクリーン。スクリーンへcanvasが転送されても(drawInRect:rect)nilスクリーンが表示される。
メソッド名、変数名、as(キャスト記号)に!?記号を付ける場合、nil checkの有無を!?が表す。delegate.someMethod?()は委譲先でsomeMethod()が実装されている際(nil check成功)には呼び出すが、nil check失敗時メソッド呼出は行われない。
変数名に!?が付いている場合、nil check後にunwrapする。
anObject as! AnObjectの意味は、Optional型であるanObject変数のnil check無でnon-Optional型のAnObjectへキャストする。(←これ間違い、swift1.2の場合)
Optional型のanObject変数をnon-OptionalなAnObjectへキャストする。anObject as AnObject!と同じ。anObject as? AnObjectはanObject as AnObject?と同じ。
型名に!?記号を付ける場合(例えば、Int?とかInt!とか)、その型名で宣言された変数はunwrap済なのか、そうで無いのかを示す。
!?を変数、メソッドに付ける場合と、宣言、キャスト時に付ける場合を分けて考える。
【上記、編集途中です。】
参考になりそうなStackOverflowの記事