variable strong protocol generic functions extension swift optional downcasting forced-unwrapping

swift - strong - Tratar un downcast forzado como opcional nunca producirá ''nil''



swift syntax (2)

He estado jugando con Swift y descubrí que cuando descargo un objeto para insertarlo en un diccionario, recibo una advertencia extraña: Treating a forced downcast to ''String'' as optional will never produce ''nil'' . Si sustituyo as con as? entonces la advertencia desaparece.

func test() -> AnyObject! { return "Hi!" } var dict = Dictionary<String,String>() dict["test"]=test() as String

La documentación de Apple dice lo siguiente.

Debido a que el downcasting puede fallar, el operador de conversión de tipo viene en dos formas diferentes. La forma opcional, as? , devuelve un valor opcional del tipo al que está intentando reducir. La forma forzada, as , intenta la caída hacia abajo y la fuerza, desenvuelve el resultado como una única acción compuesta.

No tengo claro por qué usar as? en lugar de as es correcto aquí. Algunas pruebas revelan que si cambio test () para devolver un Int en lugar de un String, el código se cerrará con un error si continúo usando as . Si cambio a usar as? entonces el código continuará la ejecución normalmente y omitirá esa declaración (el dict se mantendrá vacío). Sin embargo, no estoy seguro de por qué esto es preferible. En mi opinión, preferiría que el programa salga con un error y me haga saber que el lanzamiento no tuvo éxito, entonces simplemente ignore la declaración errónea y siga ejecutando.

De acuerdo con la documentación, debería usar el formulario forzado "solo cuando esté seguro de que el derrumbe siempre tendrá éxito". En este caso, estoy seguro de que el downcast siempre tendrá éxito ya que sé que test() solo puede devolver un String, por lo que asumo que esta es una situación perfecta para la forma forzada de down casting. Entonces, ¿por qué el compilador me da una advertencia?


Echemos un vistazo más de cerca a tu última línea y explórela para ver qué está pasando:

let temporaryAnyObject = test() let temporaryString = temporaryAnyObject as String dict["test"] = temporaryString

El error está en la segunda línea, donde le está diciendo al compilador que haga cumplir que el objeto temporaryAnyObject es definitivamente una String . El código aún se compilará (suponiendo que no trate las advertencias como errores), pero se bloqueará si el valor temporaryAnyObject no es realmente una String .

El camino as funciona, con no ? , básicamente dice "de ahora en adelante, trate el resultado de esta expresión como ese tipo SI el resultado es realmente de ese tipo; de lo contrario, nos hemos vuelto inconsistentes y ya no podemos ejecutar.

El camino as? works (with the ? ) está diciendo "a partir de ahora, trate el resultado de esta expresión como ese tipo SI el resultado es realmente de ese tipo, de lo contrario, el resultado de esta expresión es nil .

Por lo tanto, en mi ejemplo de despiece de arriba, si test() devuelve un String , entonces el downdown tiene éxito, y temporaryString ahora es un String . Si test() no devuelve una String , pero diga un Int o cualquier otra cosa que no esté subclasificada de la Cadena, entonces el comando falla y el código ya no puede continuar ejecutándose.

Esto se debe a que, como desarrollador en control completo, le dijo al sistema que se comporte de esta manera al no poner el opcional ? indicador. El comando as significa específicamente que no tolera el comportamiento opcional y que necesita que funcione el downcast.

Si hubieras puesto el ? , entonces la temporaryString sería nil , y la tercera línea simplemente eliminaría el par clave / valor "prueba" del diccionario.

Esto puede parecer extraño, pero solo porque es el comportamiento predeterminado opuesto de muchos idiomas, como Obj-C, que trata todo como opcional de manera predeterminada, y confía en que usted coloque sus propios cheques y declaraciones.

Editar - Actualización de Swift 2

Desde Swift 2, el operador abatido forzado, failable as se ha eliminado, y se reemplaza con as! , que es mucho más rápido. El comportamiento es el mismo.


Puedes resolver esta advertencia desde dos ángulos. 1. El valor que devuelve 2. El tipo que se espera que devuelva. La otra respuesta habla del primer ángulo. Estoy hablando del segundo ángulo

Esto se debe a que está devolviendo un valor forzado desempaquetado y convertido para un opcional . El compilador es como: " Si realmente quieres forzar solo la conversión de todas las opciones, entonces ¿por qué no hacer que el parámetro de retorno esperado no sea opcional? "

Por ejemplo si escribiste

func returnSomething<T> -> T?{ // I''m an optional, I can handle nils SAFELY and won''t crash. return UIViewController as! T // will never return a safe nil, will just CRASH }

Básicamente, te dijiste a ti mismo (y al compilador) que quiero manejar nil s de forma segura, pero luego, en la siguiente línea, dijiste nah, ¡no lo hago!

El compilador daría una advertencia:

Tratar un downcast forzado a ''T'' como opcional nunca producirá ''nil''

Una alternativa es eliminar el ?

func returnSomething<T>() -> T{ // I can''t handle nils return UIViewController() as! T // I will crash on nils }

Habiendo dicho eso, probablemente la mejor manera es no usar el lanzamiento de fuerza y ​​simplemente hacer:

func returnSomething<T>() -> T?{ // I can handle nils return UIViewController() as? T // I won''t crash on nils }