2015-03-06 2 views
28

При доступе UIapplication's главного окна он возвращается как UIWindow??Почему главное окно типа double optional?

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

Почему возвращаются в качестве двойного факультативного и что это значит, и если поместить в if let я должен добавить один ! после него?

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

Мой первый, хотя должен был заменить ? с ! после делегата, но это не решение.

+1

Это не: 'дополнительное окно var: UIWindow? {get set} '- ваш' делегат' является необязательным, хотя (используя '?'), что приводит к еще одному уровню опций. –

+0

Но даже когда я положил! справа от делегата, это все равно дает? – Arbitur

+0

Аналогичный вопрос здесь: http://stackoverflow.com/questions/25175544/uiwindow-does-not-have-member-named-bounds. –

ответ

23

@ Matt имеет детали, но есть (несколько попало, несколько удивительным) обходной путь. (См. Править ниже)

let window = app.delegate?.window??.`self`() 

Я оставлю понимание этой строки кода в качестве упражнения для читателя.

ОК, я лежу, давайте сломаем его.

app.delegate?.window 

ОК, пока все хорошо. На данный момент у нас есть UIWindow??, который дает нам головную боль (и я считаю, что ошибка в Swift отключается между Swift и Cocoa). Мы хотим развалить его дважды. Мы можем сделать это с опциональной цепочкой (?.), но это разворачивает и перематывает, так что мы вернулись туда, откуда мы начали. Вы можете удвоить-необязательно-цепочку, хотя, с ??., что странно, но работает.

Это замечательно, но ?? не является юридическим суффиксом. Вы должны на самом деле цепочки к чему-то. Ну, мы хотим привязать себя к себе (т. Е. «Идентичность»). Протокол NSObject дает нам метод идентификации: self.

self является метод на NSObject, но это также зарезервированное слово в Swift, поэтому синтаксис для него является `self`()

И таким образом мы получаем наше безумие выше. Делайте с ним, как хотите.

Обратите внимание, что поскольку ??. работает, вам это не требуется. Вы можете просто принять, что view is UIWindow?? и использовать ??. на нем, как view??.frame. Это немного шумно, но, вероятно, не создает никаких реальных проблем для немногих мест, в которых это необходимо.

(*) Раньше я думал об этом как об ошибке в Swift, но не фиксируется непосредственно путем дополнительной цепочки. Проблема в том, что нет никакой дополнительной привязки минус window. Поэтому я не уверен, где это место для исправления. Swift может позволить postfix-? означать «сгладить», не требуя цепочки, но это кажется странным. Я предполагаю, что правильный оператор будет interrobang delegate?.window‽: D Я уверен, что это не вызовет путаницы.

EDIT:

Joseph Lord pointed out the better solution (который очень похож на методы я использую, чтобы избежать тривиальной, если пусть, но не думал об этом, как и раньше):

let window = app.delegate?.window ?? nil // UIWindow? 

Я согласен с ним, что это правильный ответ.

+0

Это похоже на работу с добрым старым «flatMap'ping – DeFrenZ

+0

,'? .' является 'flatMap', поэтому я не уверен, что он его исправляет. –

+0

Но все же, это не компилируется (Swift 1.1) на игровой площадке. Вероятно, потому что он не знает, должен ли он возвращать 'UIWindow ??' или 'UIWindow? '(Оба будут действительными) – DeFrenZ

12

Это потому, что собственность window сама по себе сомневается (это необязательно). Таким образом, вам нужен один знак вопроса, потому что может быть или не быть свойство окна, и еще один знак вопроса, поскольку возвращаемое значение этого свойства окна само по себе является необязательным. Таким образом, мы получаем опцию с двойным оберткой (как я объясняю в своем tutorial: прокрутите вниз до окна «Совет», где я расскажу о том, что произойдет, когда необязательное свойство имеет значение «Необязательно»).

Таким образом, один из способов выразить это было бы в два этапа - один, чтобы бросить (и разворачивать что необязательно), и один, чтобы принести окно (и разворачивать что Дополнительно):

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

Теперь view - это UIWindow.

Конечно, если вы уверены в своей земле (что вы, вероятно, есть), вы можете заставить литье в первой строке и разворачиваться во второй строке. Так, в Swift 1.2:

let del = UIApplication.sharedApplication().delegate as! AppDelegate 
let view = del.window! 
+2

Как минимум в 6.3, 'delegate' имеет тип' UIApplicationDelegate? '. Необязательная цепочка должна избавиться от этого дополнительного слоя необязательно. –

+1

@RobNapier Повторно выражено. - Мне больше не нравился этот двойной вариант. На мой взгляд, Свифт идет немного далеко. – matt

+0

Согласовано. Но это было бы исправлено, если опционально-цепочка поддерживала objc-protocol-optional (что я считаю ошибкой, которой это не так). –

0

С появлением Swift2 для меня обычный обходной путь в такого рода случаях

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

О двойной факультативный! Иногда вы можете использовать double-bang (два восклицательных знака), но вы не можете использовать этот способ с необязательным привязкой. Так ... мой ремикс всего остальной кода получает вас объект UIWindow под названием window из неопционального вида:

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

Но давайте не будет тратить время и просто использовать

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

и сделать ,