Optional記号!, ?の使い方

- 宣言、ダウンキャスト、メソッド呼出、メソッド引数、左辺値、５つのケースでメモを残しておく。(Xcode7 beta1 + Swift2.0)
- 宣言

```swift:foo.swift                                                          
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.
```

- ポイント


1. 記号!, ?何れかを使って宣言すれば、Optional(nil acceptable)と見なされる。
2. Optional型には２つのstateがあって、一つはwrappedで、もう一つはunwrapped。
2. 記号の有無は、メソッド呼出時に影響でる。メソッド呼出時にwrappedなインスタンスであれば記号!を使ってメソッド呼出が必要。Optional型であってもunwrappedなら記号!不要でメソッド呼出可能。
3. Optional型で無いインスタンスに記号!を付けてメソッド呼出を行えば、コンパイルエラー発生。（例：上記のvar z）
2. Optional型であっても既にunwrappedな上記のvar xであれば記号!無しにメソッド呼出可能。(ex: print(x.distanceTo(-2)))記号!があってもOK。(ex: print(x!.distanceTo(-2)))

- ダウンキャスト

```swift:foo.swift
let delegateObj = anObject as! AppDelegate // (1)
//let delegateObj = anObject as? AppDelegate // (2)
let delegateObj = anObject as AppDelegate! // (3)
```

- ポイント

1. anObject変数のnil check無でnon-opptional型へ強制ダウンキャスト 【場合(1)】する。anObjectがnilならエラー発生する。
2. anObject変数のnil check有りでnon-opptional型へ強制ダウンキャスト 【場合(2)】、ただしキャストに失敗してもエラー発生させない。（swift2.0ではコンパイルエラー）check失敗でも。。。というよりコンパイルエラー発生。
3. opptional型へダウンキャスト 【場合(3)】、ただし、unwrap済。
4. asキーワード(?, !も付かないas)はキャストアップへ使う。例えば、UITouchからNSObjectへのキャストへ使うが、あまり使い道が無い。

- メソッド呼出

```swift:foo.swift
foo!.goToSchool() // (1)
foo?.goToSchool() // (2)
```

- ポイント

1. nil checkせずにfooインスタンスのメソッド呼出をする。check失敗時、nilに対しgoToSchool()メソッド呼出をするので、実行時にエラーが発生する。nil guardが必要。
2. nil checkしてからfooインスタンスのメソッド呼出する。check失敗時、メソッド呼出しない。fooがnilでも実行時にエラー発生しない。

- メソッド引数

宣言の時と同じ。

- 左辺値

```swift:foo.swift
    self.canvas1 = self.canvasImage1()
//    self.canvas1! = self.canvasImage1() nil found error occured.
//    self.canvas1? = self.canvasImage1() blank is drawn.

```

- ポイント

1. 左辺値に用いて値代入する際には、unwrap済みである事一見で判る!?記号が無い状態で記述しないと、実行時にエラーとなるか、nil代入されちゃう。
2. !記号付きで左辺値に記述すると、nil checkせずunwrapする。unwrapの結果nilなら定数nilへの代入は出来ないのでnil found実行時エラーが発生。unwrapの結果nilでないなら、変数の中身が上書きされる。
 
3. ?記号付きで左辺値を記述すると、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の記事](http://www.touch-code-magazine.com/swift-optionals-use-let/)