ios swift optional uiwindow

ios - ¿Por qué la ventana principal de tipo doble es opcional?



swift optional (4)

¡Oh, el doble opcional! A veces puede usar una doble explosión (dos signos de exclamación) pero no puede emitir de esa manera con el enlace opcional. Entonces ... mi remix de todo el otro código te da un objeto UIWindow llamado window del tipo no opcional:

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

Pero no perdamos el tiempo y solo usemos

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

y listo

Al acceder a UIapplication''s ventana principal UIapplication''s se devuelve como una UIWindow??

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

¿Por qué está regresando como un doble opcional y qué significa y si se coloca en un if let debería agregar uno ! ¿después de?

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

¿Mi primer pensamiento fue reemplazar ? con un ! después del delegado pero esa no era la solución.


@matt tiene los detalles, pero hay una solución alternativa (algo horrible, algo sorprendente). (Ver edición a continuación, sin embargo)

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

Dejaré la comprensión de esta línea de código como un ejercicio para el lector.

Bien, miento, analicemoslo.

app.delegate?.window

OK, hasta ahora todo bien. En este punto tenemos la UIWindow?? eso nos está dando dolor de cabeza (y creo que es un error en la desconexión de Swift entre Swift y Cocoa). Queremos colapsarlo dos veces. Podemos hacer eso con el encadenamiento opcional ( ?. ), Pero eso se desenvuelve y vuelve a envolver, así que volvemos a donde comenzamos. Sin embargo, puede hacer doble cadena opcional con ??. lo cual es extraño, pero funciona.

Eso es genial, pero ?? No es un operador de sufijo legal. Tienes que encadenar a algo. Bueno, queremos encadenarnos a sí mismos (es decir, "identidad"). El protocolo NSObject nos da un método de identidad: self .

self es un método en NSObject , pero también es una palabra reservada en Swift, por lo que la sintaxis es `self`()

Y así conseguimos nuestra locura arriba. Hazlo como quieras.

Tenga en cuenta que desde ??. funciona, técnicamente no necesitas esto. ¿Puedes aceptar que esa view es UIWindow?? y usar ??. en ella como view??.frame . Es un poco ruidoso, pero probablemente no cree ningún problema real para los pocos lugares donde debería ser necesario.

(*) Solía ​​pensar en esto como un error en Swift, pero no se puede solucionar directamente mediante el encadenamiento opcional. El problema es que no hay una window encadenamiento opcional. Así que no estoy seguro de dónde está el lugar correcto para arreglarlo. Swift podría permitir un postfix- ? significa "aplanar" sin requerir encadenamiento, pero eso se siente extraño. Supongo que el operador correcto sería delegate?.window‽ : D Estoy seguro de que eso no causaría ninguna confusión.

EDITAR:

Joseph Lord señaló la mejor solución (que es muy similar a las técnicas que he estado utilizando para evitar un trivial if-let, pero que nunca antes había pensado de esta manera):

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

Estoy de acuerdo con él en que esta es la respuesta correcta.


Con la llegada de Swift2 para mí, una solución habitual en este tipo de casos es

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


Es porque la propiedad de la window está en duda (es opcional). Por lo tanto, necesita un signo de interrogación porque puede haber o no una propiedad de ventana, y otro signo de interrogación porque el valor de retorno de esa propiedad de ventana es en sí mismo Opcional. Por lo tanto, obtenemos un Opcional doblemente envuelto (como explico en mi tutorial : desplácese hacia abajo hasta el cuadro Sugerencia donde hablo sobre lo que sucede cuando una propiedad opcional tiene un valor Opcional).

Por lo tanto, una forma de expresar esto sería en dos etapas: una para lanzar (y desenvolver ese Opcional) y otra para buscar la ventana (y desenvolver ese Opcional):

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

Ahora la view es una UIWindow.

Por supuesto, si está seguro de su terreno (que probablemente lo esté), puede forzar el lanzamiento en la primera línea y el desenvolvimiento en la segunda línea. Entonces, en Swift 1.2:

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