Swift で 2回 Unwrap が必要なケースについて調べた

More than 3 years have passed since last update.

検証環境:Xcode6.1, Swift1.1


例えば以下の様な Objective-C のコードを

[[[UIApplication sharedApplication] delegate] window].rootViewController

Swift で書き直そうとした場合、まずはこんな感じに書くと思う。

UIApplication.sharedApplication().delegate?.window?.rootViewController

しかしこれだとコンパイルエラーになる。

スクリーンショット 2014-11-15 16.46.51.png

そしてどういうことか、window? に更に Unwrap を行うことでコンパイルが通るようになる。

UIApplication.sharedApplication().delegate?.window??.rootViewController

この意味が全くわからなかったので調べたところ StackOverFlow に検証エントリーを見つけたので、まずはこちらを見て頂くと良いと思う。

http://stackoverflow.com/questions/26201456/unwrap-uiwindow-twice-from-appdelegate-in-swift


検証コード

先に挙げた記事のコードを引用させていただく。

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 が必要になる と理解しました。

間違いなどありましたらコメント頂けると幸いです。