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!