Home » Análisis » Swift 3.1 ha llegado, análisis de todos sus cambios
Swift 3.1

Swift 3.1 ha llegado, análisis de todos sus cambios

Llegó el día y las nuevas versiones de primavera de los sistemas ya están entre nosotros: iOS 10.3, watchOS 3.2, tvOS 10.2 y macOS 10.12.4. Y con ellos, ha llegado Xcode 8.3 (días antes ya llegó Swift Playgrounds 1.2), que suponen un paso importante en la evolución del lenguaje Swift: la llegada de su versión 3.1. Esta versión es totalmente retro-compatible con Swift 3.0 por lo que el mismo código que funcionaba en la versión 3.0, 3.0.1 o 3.0.2, sigue funcionando en la versión 3.1 que se acaba de lanzar. Las diferencias, no obstante, existen. No por cambios, si no porque hay cosas que ahora se pueden hacer de formas más eficientes (aunque la manera antigua siga funcionando).

Por lo tanto, vamos a hacer un repaso de esos pequeños cambios que incorpora esta nueva versión que vienen a mejorar o hacer más intuitivo aún nuestro código cuando trabajamos con Swift.

Extensiones concretas restringidas

Cuando usamos extensiones, podemos restringir su ámbito a través de instrucciones where que están limitadas a protocolos. De esta forma, si tenemos una extensión del tipo Collection y queremos poder acceder, por ejemplo, a una operación de comparación a través de un operador comparativo (como el >), debemos restringir esta extensión para que solo funcione cuando un elemento de dicho tipo conforme con un protocolo (en este caso el Comparable). Veamos un caso práctico:

En el caso expuesto estamos haciendo una función mayorQue a la que pasamos un elemento del mismo tipo de la colección que estemos usando, siempre y cuando el elemento de dicha colección se conforme con el protocolo Comparable. Es decir, que sea un tipo de dato al que puedan aplicarse los operadores comparativos <, >, ==, <=, >= y !=.

Pero ahora podemos ir más allá de los protocolos y usar tipos de datos directamente como restricción para una extensión. Por lo tanto, si queremos que esta extensión se use en una colección que sea sólo de tipo Int, por ejemplo, podemos hacer:

Esto es lo verdaderamente interesante. Acotar por tipos de datos, no solo por protocolos. Una muy buena nueva implementación que aumenta aun más las posibilidades de las extensiones ya que ya no es necesario que busquemos un protocolo que conforme con el tipo, si no que podemos usar directamente tipos de datos y que los métodos que incluyamos a través de las extensiones, solo estén disponibles para ese tipo de dato concreto.

Dos nuevos métodos en las secuencias a nivel closure funcional

Métodos como filter, map o reduce son grandes añadidos, herencia de la programación funcional y que nos permiten, mediante closures, trabajar directamente sobre secuencias de datos (colecciones) y trabajar con ellos. Pues bien, en Swift 3.1 tenemos dos nuevos métodos que se han añadido que nos permiten realizar operaciones muy interesantes.

Se trata de prefix(while:) y drop(while:) que realizan una selección de elementos ordenados siempre y cuando estos cumplan una condición determinada. Antes podíamos llamar a estos métodos sin closures, dando un parámetro de tipo entero que especificaba el total de elementos previos que queríamos recoger ( prefix) o elementos que queríamos eliminar ( drop). Pero ahora podemos usar los closures para especificar de una forma más clara, como si fuera un repeat while dentro de una secuencia, pero dentro de un closure: mientras se cumpla una condición, incluye los elementos de esta colección. Por lo tanto, lo que ha de devolver el closure es siempre un valor de tipo Bool (una condición que debe ser, verdadera o falsa).

De esta forma, mientras el sufijo de la cadena sea "Bolsón", el método devolverá elementos. Pero en el momento que una de las condiciones en la secuencia evaluada no se cumpla, se romperá la misma y entonces devolverá el resultado. Por eso nunca llega a validar al padre de Bilbo, Bungo Bolsón.

Sin embargo, curiosamente el otro método drop(while:) hace justo lo contrario. Devolverá la secuencia cuando la condición del repeat while deje de cumplirse y ahí es donde empezará a coger elementos. Justo la operación contraria.

Aquí podemos ver, en la app Swift Playgrounds, cómo se ejecutan ambos ejemplos y el resultado que devuelven.

Swift 3.1, Ejemplos 1 y 2

Inicializadores falibles en tipos numéricos

Los tipos numéricos en Swift son muchos, no solo nos referimos a los conocidos Int, Double o Float. También tenemos otros muchos según la precisión. En concreto, todos estos: Int, Int8, Int16, Int32, Int64, UInt, UInt8, UInt16, UInt32, UInt64, Float, Float80 y Double. Una de las cosas que hemos podido hacer siempre es usar los constructores de estos tipos para pasar de un valor a otro.

Ahora basta llamar a los constructores con el parámetro exactly para obtener una conversión más eficiente que rechace aquellos valores que no se podrán convertir porque pierden precisión. Imaginemos que tenemos una carga de datos que envía datos enteros y con precisión decimal a la vez, y que además son cadenas (por ejemplo, porque pueden venir de un JSON o una carga de datos de otro tipo). Con esta conversión tendremos una forma más segura de capturar solo aquellos datos que sabemos a ciencia cierta que son enteros y no perderán precisión alguna.

Lo que obtendremos con este ejemplo es un array de tipos Int, convertidos de forma segura, de forma que el contenido que quedaría en valoresInt sería: [5, 7, 3, 1]. Solo aquellos valores que han podido ser convertidos e interpretados como Int que era el objetivo. El resto, se han rechazado.

Genéricos anidados

Ahora podemos anidar diferentes tipos que usen un mismo genérico T, por ejemplo. De esta forma, podemos crear una clase genérica dentro de otra que usen ese mismo tipo.

Podemos incluir el tipo T dentro de cualquier tipo anidado dentro de otro.

Conversión de closures que no escapan en closures que escapan

El cambio de los closures que escapan o no, fue una de las funciones más importantes de Swift 3. De ser por defecto que escapaban, ahora lo son que no escapan. De esta forma, si tenemos un closure que no será ejecutado directamente en la función que lo recibe como parámetro, tenemos que indicar la cláusula @escaping para indicar que efectivamente este será ejecutado fuera del ámbito de la función que lo recibe.

Pero ahora podemos ir más allá. Podemos recoger un closure que es enviado para que no escape, y enviarlo como closure que escapa a partir de un nuevo método que nos permite pasar este que no escapa hacia otro pero que esta vez sí escape. Usando el método: withoutActuallyEscaping.

Imaginemos este caso:

La función funcionConClosureQueEscapa recibe un parámetro de tipo @escaping porque esta función no se encargará de ejecutar el closure. Lo que hará será meterlo en el array completionHandlers. Pero la función funcionConClosureQueNoEscapa no requiere escape de ningún tipo porque ella misma ya ejecuta el closure que es el que recibe como parámetro.

Pero, ¿qué pasa si por cualquier motivo queremos convertir este closure que no escapa en uno que sí?. Usamos withoutActuallyEscaping con un closure que recibirá un parámetro que es el propio closure ya convertido en un tipo que sí escapa, y por lo tanto podremos (por ejemplo), incluirlo en el citado array.

Como vemos, recibe un parámetro que hemos llamado escapableClosure que nos permite añadirlo al array, por lo tanto, ha convertido **un closure que no escapa en uno que sí lo hace.

Disponibilidad de versión

Por último, una de las cosas importantes que tiene Swift es la posibilidad de preguntar por la versión del lenguaje para que evalúe o no alguna expresión que pertenezca a una versión anterior de sintaxis.

Podemos usar como comprobador de versión para un código acotado en un ámbito #if swift(&gt;=3.1) y tendrá en cuenta que esté debe ser ejecutado cuando la versión sea igual o superior a la versión 3.1 del lenguaje.

Y lo más importante, si queremos usar una API que ha sido borrada en Swift 3.1, podemos usar la siguiente directiva:

Pequeños grandes cambios

Esto es solo es lo referente al lenguaje de por sí. Una versión en la que han colaborado multitud de ingenieros, no solo de Apple, también de otras empresas como IBM o el propio Chris Lattner quien se ha encargado de dar el visto bueno a determinadas incorporaciones importantes.

En otro especial hablaremos de los cambios del gestor de paquetes o de las nuevas incorporaciones en la versión Linux. Ya sabéis que ahora con Xcode 8.3 o Swift Playgrounds 1.2 podéis probar estos cambios. Contadnos qué tal, esperamos vuestras opiniones en los comentarios. 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 Cambios

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

El cambio de versión de Swift 3 a 4 es algo que provoca miedos e inseguridades. La memoria del pesado cambio a la versión 3 nos trae malos recuerdos, pero nada más lejos de la realidad en este caso. A fecha 31 de mayo, solo 3 cosas harán nuestro código incompatible. Descúbrelas en este análisis y cuales serán las simples soluciones en caso que esto nos afecte.

  • tecaware

    Enhorabuena por tu iniciativa de análisis crítico y difusión de la plataforma. ¿Sabes si es posible cambiar el idioma a inglés en las nuevas versiones de los campos de Playgrounds sin tener que modificar el sistema o recurrir a versiones obsoletas? Me parece un buen sistema para trabajar el idioma además de la programación.