web-dev-qa-db-ja.com

タイプdoubleのメインウィンドウがオプションであるのはなぜですか?

UIapplication'sメインウィンドウにアクセスすると、UIWindow??として返されます。

let view = UIApplication.sharedApplication().delegate?.window // view:UIWindow??

ダブルオプションとして返されるのはなぜですか。それはどういう意味ですか。if letに入れる場合は、その後に!を1つ追加する必要がありますか?

if let view = UIApplication.sharedApplication().delegate?.window!

私の最初は、デリゲート後に?!に置き換えることでしたが、それは解決策ではありませんでした。

39
Arbitur

@mattに詳細がありますが、(やや恐ろしい、やや素晴らしい)回避策があります。 (ただし、以下の編集を参照してください)

_let window = app.delegate?.window??.`self`()
_

このコード行の理解は、読者の練習問題として残しておきます。

OK、私は嘘をつきます、それを分解しましょう。

_app.delegate?.window
_

OK、これまでのところ良いです。この時点で、頭痛の種となっている_UIWindow??_があります(そして私はそれが swiftのバグ SwiftとCocoa)の間を切断します。 2回折りたたんだいです。オプションのチェーン(_?._)を使用してこれを行うことができますが、それはアンラップして再ラップするため、元の場所に戻ります。ただし、_??._を使用すると、ダブルオプションチェーンを使用できます。これは奇妙ですが、機能します。

それは素晴らしいことですが、_??_は正当なサフィックス演算子ではありません。あなたは実際に何かに連鎖しなければなりません。さて、私たちはそれ自体にチェーンバックしたいと思います(つまり「アイデンティティ」)。 NSObjectプロトコルは、IDメソッドselfを提供します。

selfNSObjectのメソッドですが、Swiftの予約語でもあるため、構文は`self`()です。

そして、私たちは上記の狂気を手に入れます。あなたがそうするようにそれをしてください。

_??._は機能するため、技術的には必要ないことに注意してください。 viewが_UIWindow??_であることを受け入れ、_??._のように_view??.frame_を使用することができます。少しうるさいですが、必要な場所がいくつかあるので、おそらく実際の問題は発生しません。

(*)以前はこれをSwiftのバグと考えていましたが、オプションのチェーンで直接修正することはできません。問題は、windowを過ぎたオプションのチェーンがないことです。そのため、修正するのに適切な場所がどこにあるのかわかりません。 Swift接尾辞-_?_は、連鎖を必要とせずに「フラット化」を意味する可能性がありますが、それは奇妙に感じます。正しい演算子はインテロバング_delegate?.window‽_:D I混乱を招くことはないと確信しています。

編集:

Joseph Lordがより良い解決策を指摘しました (これは、些細なif-letを回避するために使用してきた手法と非常に似ていますが、以前はこのように考えていませんでした):

_let window = app.delegate?.window ?? nil // UIWindow?
_

私はこれが正しい答えであると彼に同意します。

30
Rob Napier

これは、windowプロパティ自体が疑わしいためです(オプションです)。したがって、ウィンドウプロパティがある場合とない場合があるため、1つの疑問符が必要です。また、そのウィンドウプロパティの戻り値自体がオプションであるため、別の疑​​問符が必要です。したがって、二重にラップされたオプションが得られます( チュートリアル で説明しているように:オプションのプロパティにオプションの値がある場合に何が起こるかについて説明するヒントボックスまでスクロールします)。

したがって、これを表現する1つの方法は、2つの段階になります。1つはキャスト(およびアンラップthatオプション)、もう1つはウィンドウのフェッチ(およびアンラップ)です。 thatオプション):

if let del = UIApplication.sharedApplication().delegate as? AppDelegate {
    if let view = del.window {

これで、viewはUIWindowになりました。

もちろん、自分の立場が確かな場合は(おそらくそうですが)、最初の行でキャストを強制し、2番目の行でアンラップすることができます。したがって、Swift 1.2:

let del = UIApplication.sharedApplication().delegate as! AppDelegate
let view = del.window!
18
matt

ああ、ダブルオプション!ダブルバン(2つの感嘆符)を使用できる場合もありますが、オプションのバインディングではそのようにキャストできません。つまり...他のすべてのコードをリミックスすると、オプションではない種類のwindowというUIWindowオブジェクトが得られます。

guard let w = UIApplication.shared.delegate?.window, let window = w else { return }

しかし、時間を無駄にせず、ただ使用しましょう

let window = UIApplication.shared.delegate!.window!!

そして行われる。

1
Dan Rosenstark

私にとってSwift2の登場により、この種の場合の通常の回避策は次のようになります。

if let _window = UIApplication.sharedApplication().delegate?.window, window = _window {
    // Some code... i.e.
    let frame = window.frame
}
0
user1317655