Home » Análisis » Los cambios en Swift 4 que harán tu código incompatible: 3 por ahora
Swift 4 Cambios

Los cambios en Swift 4 que harán tu código incompatible: 3 por ahora

Leo un estupendo artículo de Bart den Hollander, desarrollador en la compañía Xebia, y experto en Swift. En su Medium, publica un estupendo análisis donde nos cuenta qué evoluciones aprobadas para el lenguaje Swift en su versión 4 serán responsables de incompatibilidad de código y necesitarán ser corregidas para que este vuelva a compilar. En total, a fecha 31 de mayo de 2017, son solo 3. Y hay que tener presente que ya tenemos casi la nueva implementación de los tipos String que supuestamente iban a provocar más incompatibilidades.

Y ojo, no hablamos de cambios en la forma de operar: hablamos de cosas que funcionaban en la versión 3.0 o 3.1 y que en la 4 dejarán de funcionar. E insistimos: por ahora (a falta de unos días para la WWDC donde se cerrará la versión de Swift 4 y dejarán de aprobarse evoluciones, pasándose a una fase de corrección) solo 3 cosas provocarán que nuestro código no compile, siempre y cuando hayamos hecho alguna de las cosas que a partir de la versión 4 no podrán hacerse.

Cambios en Swift 4

De todo el listado que se ve arriba, solo lo marcado en negrita supone un cambio por el que el código de la versión 3 dejará de funcionar en la 4, siempre y cuando hayamos hecho alguna de estas implementaciones que cambian. Vamos a pasar a analizar dichos cambios, pero no usando los ejemplos del señor Hollander, sino explicándolos a nuestra manera para intentar dejarlo más claro, en base a la documentación oficial.

Distinguir entre tuplas simples y funciones multi-argumento (SE-0110)

En Swift 3 teníamos un uso ambiguo de las tuplas cuando queríamos usar bien una o bien simplemente una función de múltiples parámetros. Como ejemplifica el caso en el hilo oficial de este cambio, nosotros ahora tenemos estas dos casuísticas.

La función fn1 tiene dos argumentos de entrada, pero si en el closure solo contemplamos uno ( x) lo que obtendremos es que x será una tupla de tipo (Int, Int) que contendrá ambos valores de los parámetros. Sin embargo, cuando hacemos algo similar a fn2, la cosa cambia. Si en vez de poner un solo parámetro de entrada del closure como antes, ponemos dos: x e y, entonces x será un Int, y otro y no habrá tupla alguna. Esto, como poco, es ambiguo y confuso y no define correctamente los casos. Por lo tanto, ahora no va a funcionar fn1.

Si queremos que fn1 sea un closure con una tupla de tipo (Int, Int) tendremos que definir el tipo de entrada de parámetro del closure como ((Int, Int)), poniendo ambos valores entre dobles paréntesis que acoten por un lado el caso de la tupla y por otro el de los dos argumentos. Por lo tanto nuestro código quedaría así en Swift 4.

Si hacemos el caso fn1 planteado en el primer ejemplo, tendremos un error que nos dirá error: closure tuple parameter '(x: Int, y: Int)' does not support destructuring o lo que es lo mismo: el parámetro tupla del closure no soporta desestructuración. Solo en dicho caso, tendremos un error: cuando intentemos usar el argumento de entrada de un closure (que ahora se puede) como un valor que infiera una tupla al tener más de un valor como parámetro de entrada.

Limitación de inferencia de la cláusula @objc

Este cambio implicará que si tenemos un proyecto que use Swift y Objective-C, de pronto haya componentes que queremos que creen una interfaz visible para Objective-C que dejarán de funcionar. Básicamente, lo que hace es obligar a incluir la cláusula @objc en mayor detalle y no suponer que puestos en el elemento de mayor nivel, todo lo que deriva de este será también visible para el otro lenguaje de Apple.

El cambio SE-0160 que puedes leer aquí lleva implícito que ahora si creamos una subclase de NSObject los elementos en ella no serán expuestos a Objective-C, habrá que indicarlo explícitamente. Tampoco las funciones de tipo dynamic serán expuestas y habrá que usar @objc. Esto afecta directamente, por ejemplo, a los test unitarios con XCTest ya que esta clase está implementada en Objective-C. Hasta ahora, bastaba crear una subclase de un NSObject en Objective-C como cualquier controlador, y todas las propiedades y métodos del mismo se exponían a través de Objective-C.

Pero esto es un problema para el compilador, porque el linkado entre Swift y Objective-C es pesado para este y dar por supuesto que todos los componentes de nuestras clases que hereden de hijos de NSObject van a tener que estar expuestas a Objective-C desde Swift hace que sea poco eficiente.

El código de arriba, dejará de ser usable desde Objective-C y cualquier elemento que lo use, como XCTest. Pero tenemos dos formas de solucionarlo: o bien usamos @objc solo en aquellos métodos o propiedades que realmente usamos o (la otra opción) usamos la nueva directriz @objcMembers que nos indica específicamente que son miembros de Objective-C y han de ser expuestos a este lenguaje, replicando la funcionalidad que teníamos en Swift 3.

En este caso solo valor1 y el método metodo1(Int:) serían visibles desde Objective-C, con lo que mejora la eficiencia en compilación. Pero si queremos que toda la clase sea visible podemos hacer esto.

De esta forma, toda la clase será expuesta: valor1, valor2 y el método metodo1. Pero ojo, porque metodo2 no lo será. ¿Por qué? Porque usa una tupla como valor de devolución, implementación que no tiene equivalente en Objective-C y por lo tanto no puede usarse en este lenguaje.

Mejor interacción entre declaraciones privadas y extensiones

El último cambio que puede provocar errores, es una simple afinación que arregla un fallo poco lógico. Ahora mismo, si intentamos en una extensión de una clase, acceder a una propiedad que fue declarada como private o fileprivate y la extensión está en otro fichero, no podemos acceder a ella. Esto va a cambiar. Ahora cualquier propiedad o elemento declarado como private o fileprivate será accesible por una extensión del propio tipo. Nada más simple.

Pocos cambios, muchas mejoras…

Lo hemos comentado alguna vez y lo volvemos a repetir. Sí, Swift 4 tendrá cambios en el código que podrían provocar que nuestro código dejara de funcionar, pero a fecha 31 de mayo los casos en que esto sucede son tan específicos, que realmente arreglarlo es algo trivial. Tal vez el cambio de mayor calado sea lo referente a la directiva @objc, pero por otro lado nos traerá cosas muy interesantes y prácticas, como una compilación más rápida y ligera para la CPU en términos de ejecución, al no verse forzado a exponer a Objective-C todas y cada una de las propiedades o métodos que se incluyen en cualquier subclase de NSObject.

Así que miedo 0 y a afrontar con mucha ilusión la nueva versión y veremos qué nos depara la próxima WWDC. Sin duda va a ser una semana intensa. Un saludo y Good Apple Coding.

Acerca de Julio César Fernández

Analista, consultor y periodista tecnológico, desarrollador, empresario, productor audiovisual, actor de doblaje e ingeniero de vídeo y audio.

Otras recomendaciones

Swift 4

Swift 4, así es la nueva versión del lenguaje

Desde que se lanzó Swift 3.1, ya existe la versión 4 en versión preliminar para ser descargada y probada. A solo pocos días del comienzo de la WWDC y el lanzamiento de Xcode 9, nos bajamos la versión preliminar de Swift 4 y probamos algunas de sus nuevas funciones, que os explicamos en este interesante análisis. Miedo 0, cambios pocos, muchas interesantes novedades que mejorarán nuestra productividad.