2639


Swiftの勉強中に`var cellSize: CGFloat!` という記述が出てきました。

swiftではOptional型以外は値としてnilを取れないので、Optionalに変換してるのだと思うのですが
別の場所ではOptional型の宣言には`?`をつけると出ていました。

試しに`CGFloat!`を`CGFloat?`に置き換えてみたのですが、すぐにはエラーがでないようです。

この2つの表現にはどのような違いがあるのでしょうか？


CC BY-SA 3.0
2014-12-26T09:17:55.720
2636
2015-01-02T04:30:40.933
3271
question
swift
`var foo: Type!` と`var foo: Type?` の違い


`T?` は `Optional<T>` の省略形なのに対して、`T!` は `ImplicitlyUnwrappedOptional<T>`
の省略形です。

`Optional<T>` が `nil` を許容（nil か T型
が入る）するために使われるのに対し、`ImplicitlyUnwrappedOptional<T>` は `Optional<T>`
を暗黙的にアンラップ（生の `T` の状態に）する際に使用されます。

詳細については、[Qiita に Optional
型のまとめ](http://qiita.com/cotrpepe/items/518c4476ca957a42f5f1) がありますので、参照ください。


CC BY-SA 3.0
2014-12-26T09:46:46.640
2637
2014-12-26T10:36:11.807
2014-12-26T10:36:11.807
2944
2944
2636
answer


## `?` と `!` の主な違い

`?` で作られた変数型は、Optional な値として扱われます。実質は `Optional<Type>`
型になります。これは質問内容の認識で合っています。

`!` で作られた値は、暗黙的にアンラップされる Optional な値 ( implicitly unwrapped optionals )
となります。実質は、 `ImplicitlyUnwrappedOptional<Type>`
型になっており、メソッドコールや、値参照がまるでラップされていないかのように、`nil` チェックなしでできるようになっています。

[code]

    var cellSize: CGFloat? = <初期化文>; // cellSize は、 Optional<CGFloat> 型
    println(cellSize!);                 // 強引に値をアンラップした
    cellSize!.getSummation() // 強引にアンラップしてメソッドを呼び出した (RuntimeError の危険あり)
    cellSize?.getSummation() // nil であれば返り値は Optinal で返る 
    if (let size = cellSize) {  // nil チェックを含んだアンラップ
        // nil ではなかった場合の処理
    }
    
    var cellSize: CGFloat! = <初期化文>; // cellSize は、 Optional<CGFloat> 型です
    println(cellSize);      // 強引に値をアンラップした
    cellSize.getSummation() // 強引にアンラップしてメソッドを呼び出した (RuntimeError の危険あり)
    
[/code]

## 使用用途はどう違うのか

では、使用用途としての違いってなんでしょうか。`!` は `nil` チェックをしなくても済むので、利用するのが楽に見えます。ただし、もちろん欠点として
保持値が `nil` であれば `RuntimeError` が発生する危険が残ります。( Optional にするけど、 `nil`
チェックするのは自由ですよ、ということはチェック抜けを誘発する。) ですので、 `nil`
チェックを強制する手段があるのに、それを潜り抜ける危険がある記法である 「 **`!` を普段から使うべきではなく、いつも `?` を使うのが良い**」
です。

質問で書かれたように、「Swift では Optional 型以外は値として `nil` をとれない」ということを理解されていると思います。`!`
を使うと見た目は `nil` を初期値として許容したような変数となります。ですので、例えば、「 **普段は絶対に`nil`
にならないが、オブジェクトの初期化順でどうしても初期値が `nil` でなければならない場合に `!` を使用する**」とよいでしょう。

参考: [Swift Programming Language
Guide](https://developer.apple.com/library/mac/documentation/Swift/Conceptual/Swift_Programming_Language/OptionalChaining.html#//apple_ref/doc/uid/TP40014097-CH21-XID_368)


CC BY-SA 3.0
2014-12-26T10:39:07.877
2639
2014-12-26T11:07:07.597
2014-12-26T11:07:07.597
4978
4978
2636
answer


すでに回答にあるとおり、以下の理解でいいと思います。

> 普段は絶対に nil にならないが、オブジェクトの初期化順でどうしても初期値が nil でなければならない場合に ! を使用する

具体的なユースケースですが、たとえばViewControllerのインスタンス変数を、そのVC（子VC）を呼び出す親VCが与えた必須のパラメータで初期化する場合などでしょうか。そういうインスタンス変数は必ずパラメータが渡されると想定するとnilにはなりませんが、子VCが初期化される時点では初期化できないため、viewDidLoadなどで親VCのパラメータを受け取るまで初期化を遅延しなければなりません。

この状況がまさに、「絶対にnilにはならないが、オブジェクトの初期化順でどうしても初期値がnilでなければならない場合」です。そこで、 `T?`
を使うことで、 `T?` のように煩雑になることなくインスタンス変数を使うことができます。


CC BY-SA 3.0
2015-01-02T04:30:40.933
2933
2015-01-02T04:30:40.933
114
2636
answer