Novedades en Swift 5.2

0
106
    1. Introducción
    2. Expresiones de keypath como funciones
    3. Valores invocables de tipos nominales
    4. Los subscript con argumentos predeterminados
    5. El orden de filtrado diferido ha cambiado
    6. Diagnósticos nuevos
    7. Conclusiones
    8. Referencias

Introducción

Swift 5.2 llegó con Xcode 11.4 e incluye un puñado de cambios de idioma junto con reducciones en el tamaño del código y el uso de memoria, además de una nueva arquitectura de diagnóstico que lo ayudará a comprender y resolver los errores más rápido. En este artículo, analizaré lo que las novedades en Swift 5.2 con algunos ejemplos prácticos para que se pueda ver por sí mismo cómo han evolucionado las cosas. Te animo a que sigas los enlaces a las propuestas de Swift Evolution para obtener más información.

Expresiones de key path como funciones

SE-0249 introdujo un maravilloso acceso directo que nos permite usar las rutas de teclado en un puñado de circunstancias específicas.

La propuesta de Evolution describe esto como ser capaz de usar «\Root.value donde Root -> Value está permitido», pero lo que significa es que se puede recuperar una propiedad de un objeto usarlo como key path: Car.licensePlate

Esto se entiende mejor como un ejemplo, así que aquí hay un tipo User que define cuatro propiedades:

Podríamos crear alguna instancia de esa estructura y ponerla en una matriz, como esta:

Ahora para la parte importante: si deseas obtener una matriz de todos los nombres de usuarios, puedes hacerlo utilizando una key path como esta:

Anteriormente, habría tenido que escribir un cierre para recuperar el nombre a mano, así:

Este mismo enfoque funciona en otro lugar: en cualquier lugar donde anteriormente hubiera recibido un valor y pasado una de sus propiedades, ahora puede usar una key path (ruta clave). Por ejemplo, esto devolverá a todos los usuarios que puedan votar:

Y esto devolverá a los mejores amigos para todos los usuarios que tengan uno:

Valores invocables de tipos nominales definidos por el usuario

SE-0253 introduce valores invocables estáticamente a Swift, que es una forma elegante de decir que ahora puedes llamar a un valor directamente si tu tipo implementa un método llamado callAsFunction(). No necesita ajustarse a ningún protocolo especial para que este comportamiento funcione; solo se necesita agregar ese método a tu tipo.

Por ejemplo, podríamos crear una estructura que tenga propiedades para lowerBound y upperBound, y luego añadir callAsFunction para que cada vez que llames a un valor de Dice obtengas una tirada aleatoria:

Eso imprimirá un número aleatorio del 1 al 6, y es idéntico a solo usarlo callAsFunction() directamente. Por ejemplo, podríamos llamarlo así:

Swift adapta automáticamente sus sitios de llamadas en función de cómo callAsFunction() se define. Por ejemplo, puedes agregar tantos parámetros como desees, puedes controlar el valor de retorno e incluso puedes marcar métodos como mutating si es ​​necesario.

Por ejemplo, una estructura StepCounter que rastrea lo lejos que alguien ha caminado e informa si alcanzó su objetivo de 10,000 pasos:

Para un uso más avanzado, callAsFunction() admite ambos throws y rethrows, e incluso puedes definir varios callAsFunction() métodos en un solo tipo: Swift elegirá el correcto según los parámetros de la llamada, al igual que la sobrecarga regular.

Los subscript ahora pueden declarar argumentos predeterminados

Al agregar los subscript personalizados a un tipo, ahora puedes usar argumentos predeterminados para cualquiera de los parámetros. Por ejemplo, si tuviéramos una estructura PoliceForce  con un subscript personalizado para leer a los oficiales de la fuerza, podríamos agregar un default parámetro para enviar de vuelta si alguien intenta leer un índice fuera de los límites del array:

Esto imprimirá «Amy» y luego «Uknown», y esto último se debe a que no hay un oficial en el índice 5. Ten en cuenta que debes escribir sus etiquetas de parámetros dos veces si deseas que se usen, porque los subscript no usan etiquetas de parámetros de lo contrario.

Entonces, como uso default default en mi subscript, puedo usar un valor personalizado como este:

El orden de filtrado diferido ahora se invierte

Hay un pequeño cambio en Swift 5.2 que podría causar que su funcionalidad se rompa: si usas una secuencia lazy como una matriz y le aplicas varios filtros, esos filtros ahora se ejecutan en el orden inverso.

Por ejemplo, este código a continuación tiene un filtro que selecciona nombres que comienzan con S, luego un segundo filtro que imprime el nombre y luego devuelve verdadero:

En Swift 5.2 y versiones posteriores, se imprimirán «Samwell» y «Stannis», porque después de que se ejecuta el primer filtro, esos son los únicos nombres que quedan para entrar en el segundo filtro. Pero antes de Swift 5.2, habría devuelto los cuatro nombres, porque el segundo filtro se habría ejecutado antes que el primero. Esto fue confuso, porque si eliminabas el lazy código, el código siempre devolvería solo Samwell y Stannis, independientemente de la versión Swift.

Esto es particularmente problemático porque su comportamiento depende de dónde se esté ejecutando el código: si ejecuta el código Swift 5.2 en iOS 13.3 o anterior, o macOS 10.15.3 o anterior, obtendrás el antiguo comportamiento hacia atrás, pero el mismo código que se ejecuta en los sistemas operativos más nuevos dará el nuevo comportamiento correcto.

Por lo tanto, este es un cambio que puede causar interrupciones sorpresivas en su código, pero con suerte es solo un inconveniente a corto plazo.

Diagnósticos nuevos y mejorados

Swift 5.2 introdujo una nueva arquitectura de diagnóstico que tiene como objetivo mejorar la calidad y la precisión de los mensajes de error emitidos por Xcode cuando comete un error de código. Esto es particularmente evidente cuando se trabaja con código SwiftUI, donde Swift a menudo produciría mensajes de error falsos positivos.

Por ejemplo, un código como este:

Eso intenta vincular una TextField vista a una @State propiedad de tipo Int, que no es válida. En Swift 5.1, esto causó un error para el frame() modificador que decía ‘Int’ no es convertible a ‘CGFloat?’ , pero en Swift 5.2 y versiones posteriores, esto identifica correctamente que el error es el $name enlace: No se puede convertir el valor de tipo Binding<Int> al tipo de argumento esperado Binding <String> .

Puede encontrar más información sobre la nueva arquitectura de diagnóstico en el blog Swift.org .

Conclusiones

El proyecto Swift ha alcanzado un hito crítico de madurez de los fundamentos básicos, proporcionando estabilidad para que los usuarios inviertan en usar Swift en serio. En las plataformas de Apple como macOS e iOS, la llegada de ABI y la estabilidad del módulo ha permitido la creación de los frameworks binarios estables. Además, Swift Package Manager, que tiene soporte integrado tanto en Xcode como en otros IDEs, proporciona una solución multiplataforma para construir y distribuir bibliotecas Swift. En conjunto, estos forman los ingredientes críticos para fomentar el desarrollo de un floreciente ecosistema de software Swift.

Referencias

  1. Swift.org blog
  2. Apple Swift repo
  3. New Diagnostic Architecture
  4. Swift 5.2 Release changes

 

Dejar respuesta

Please enter your comment!
Please enter your name here