検証環境:Xcode6.1, Swift1.1
例えば以下の様な Objective-C のコードを
[[[UIApplication sharedApplication] delegate] window].rootViewController
Swift で書き直そうとした場合、まずはこんな感じに書くと思う。
UIApplication.sharedApplication().delegate?.window?.rootViewController
しかしこれだとコンパイルエラーになる。
そしてどういうことか、window?
に更に Unwrap を行うことでコンパイルが通るようになる。
UIApplication.sharedApplication().delegate?.window??.rootViewController
この意味が全くわからなかったので調べたところ StackOverFlow に検証エントリーを見つけたので、まずはこちらを見て頂くと良いと思う。
検証コード
先に挙げた記事のコードを引用させていただく。
import Foundation
@objc protocol MyApplicationDelegate {
optional var myWindow: MyWindow? { get set }
}
class MyWindow : NSObject {
var rootViewController: Int?
init(number: Int) {
rootViewController = number
}
}
class MyAppDelegate: MyApplicationDelegate {
var myWindow: MyWindow?
init() {
myWindow = MyWindow(number: 5)
}
}
class MyApplication: NSObject {
var myDelegate: MyApplicationDelegate
override init() {
myDelegate = MyAppDelegate()
}
}
let myApplication = MyApplication()
println(myApplication.myDelegate.myWindow??.rootViewController)
1つ目のポイントは protocol の定義
optional var myWindow: MyWindow? { get set }
MyWindow の optional 型プロパティ自体を optional
扱いで定義している。
2つ目のポイントは MyApplication の定義
var myDelegate: MyApplicationDelegate
myDelegate
の型を MyApplicationDelegate
で定義している。
MyApplication
を使わない方が自分的に分かりやすかったので、以下の様なコードでも検証してみた。
var delegateA :MyApplicationDelegate
delegateA = MyAppDelegate()
// Unwrap が2回必要
delegateA.myWindow??.rootViewController
if let delegateB = delegateA as? MyAppDelegate {
// Unwrap 1回で良い
delegateB.myWindow?.rootViewController
}
結論
継承している protocol の型でクラスを保持している場合、その protocol に optional
で実装定義されているものが実装されている保証が無い。そのため、optional実装定義されているものに対して Unwrap が必要になる様だ。
さらにその optional
実装定義されたものの型が optional型だった場合は当然 Unwrap しないといけない。
上記の様なケースの場合、 2回 Unwarp が必要になる
と理解しました。
間違いなどありましたらコメント頂けると幸いです。