Swift 5.9 Novedades
Ha sido publicada la versión 5.9 de Swift, el lenguaje de programación preferido por la comunidad Apple Developer para el desarrollo de software en sus distintas plataformas: iOS/ipadOS, macOS, watchOS, tvOs y visionOS. Esta nueva iteración de Swift, soportada en Xcode 15.1, viene con numerosas características que favorecen la expresividad, claridad y limpieza del código a la vez que elimina en su mayor parte el código repetitivo sumando tiempo útil al desarrollador. Además introduce nuevos conceptos como tipos no copiables y una forma útil de administrar, programáticamente, el ciclo de vida de una variable.
Entre sus novedades están:
* If/switch como expresiones* Un sistema de generación de macros expresivos
*Empaquetamiento de parámetros en funciones
*Nuevo concepto de struct o enum no copiable: ~Copyable
*Nuevo operador consume para controlar el alcance o ciclo de vida de una variable o tipo.
*Soporte para interoperabilidad bidireccional con C++
*Nueva Macro para marcar clases como ObservableObject
Veámoslo con un poco más de detalles.
If/switch como expresiones(SE-0380):
Ahora podemos utilizar las estructuras condicionales if/switch para obtener el valor directamente de una variable. Es decir, pueden actual como expresiones asignables a una variable. Veamos un ejemplo:
import SwiftUI
let color : Color = if myGenere == "M" {.blue} else {.pink}
let color : Color = switch myGenere {
case "M": .blue
case "H": .pink
default: .black
}
Esta nueva técnica cobra relevancia en las variables computadas donde sabemos que la palabra return puede ignorarse:
@State private var color : Color {
switch myGenere {
case "M": .blue
case "H": .pink
default: .black
}
Sistema de Macros expresivos(SE-0382, SE-0389, SE-0397):
Las macros son un recurso que nos permite reducir el texto repetitivo a la vez que nos ayudan a crear bibliotecas de código más expresivas. Son similares a funciones, pero no pertenecen a su código. Las macros utilizan la biblioteca SwiftSyntax para generar código que luego será insertado en su código de producción. De esta forma ayudan a la generación de código reutilizable a la vez que contribuyen a mantener el enfoque claro y expresivo de Swift.
Una macro se compone de un nombre precedido del símbolo @. Su uso en el código resulta natural e intuitivo. Veamos un ejemplo tomado del sitio web de Swift.org:
// Move storage from the stored properties into a dictionary,
// turning the stored properties into computed properties.
@DictionaryStorage
struct Point {
var x: Int = 1
var y: Int = 2
}
Otras de las ventajas de las macros es lo relativo a la observación de cambios en objetos: Antiguamente se tenia que ajustar la clase obervada al protocolo @ObservableObject y marcar las propiedades a verificar con @Published. Esto generaba mucho código repetitivo. Ahora, con la macro @Observable todo este proceso se simplifica. Veamos un ejemplo:
@Observable final class User{
var name : String
var edad : Int
init(name: String, edad: Int) {
self.name = name
self.edad = 10
}
}
Luego para hacer uso de esta clase:
struct vista : View {
private var nombre : User = User(name: "Yorjandis", edad: 25)
var body: some View {
VStack{
Text(nombre.name)
Button("OK"){
nombre.name = "Juancito"
}
}
}
}
Las Macros en Swift se escriben con un enfoque potente y flexible. Similar a una función pueden aceptar parámetros para modificar su comportamiento de una manera dinámica.
Actualmente, esta versión de Swift admite macros en macOS y Linux, y próximamente Windows.
Empaquetado de parámetros en funciones:
Esta nueva opción nos permite escribir tipos y funciones genéricas con una cantidad arbitraria de parámetros, en una forma concisa y elegante. Esto viene a solucionar el problema del limite superior de parámetros posibles. Por ejemplo, para definir una función genérica que compruebe un número albitrario de parámetros como nil, tendríamos que hacer uso de sobrecarga para abarcar todas las longitudes posibles de parámetros. Esto nos lleva a establecer un límite lógico superior. Ahora con la nueva notación de parámetros empaquetados podemos eliminar este inconveniente:
Func ComprobarValorNulo<each setValores>(setValoresPosibles : repeat (each setValores)?)->(repeat [each setValores?]){
Return (repeat [each setValores?])
}
Nuevo concepto de struct o enum no copiable: ~Copyable (SE-0390)
Swift 5.9 introduce el concepto de tipos no copiables que significa que solo puede haber una instancia en memoria. Se puede cambiar de propietario de la instancia, pero solo habrá una sola referencia a dicha instancia. Esto permite el acceso a una única instancia desde muchos lugares. Se ha intriducido una nueva sintaxis para definir este comportamiento: ~Copyable. Por ejemplo:
struct User: ~Copyable {
var name: String
}
Let user1 = User(name: “juan”)
Let userCopy = user1
Print(user1.name) //!ERROR el compilador nos dirá que este tipo ya ha sido consumido.
Al hacer la copia de la instancia de user1 a userCopy se ha cambiado el propietario de la instancia. Ya user1 es nil porque su valor ha sido “Consumido”.
Esta restricción también se aplica a los parámetros de tipo no copiables adicinando dos nuevas palabras de lenguajes: consuming y borrowing. La primera le indica a la función que el tipo no copiable pasado como parámetros será consumido al finalizar la función. La segunda palabra “borrowing” o borrador le indica a la función que debe tomar prestado una copia de solo lectura del valor. Por ejemplo:
struct Persona : ~Copyable{
let name : String
}
func test(){
let p1 = Persona(name: "juan")
consumir(a: p1)
print(p1.name) //Error!! El valor de P1 ha sido consumido al finalizar la func consumir(a : )…
}
func test2(){
let p1 = Persona(name: "juan")
NoConsumir (a: p1)
print(p1.name) //el valor aún puede ser leído porque no se ha consumido
}
func consumir(a : consuming Persona){
print(a.name)
}
func NoConsumir(a : borrowing Persona){
print(a.name)
}
Soporte para interoperabilidad bidireccional con C++
Swift 5.9 introduce una amplia interoperabilidad con el lenguaje C++ y ObjectiveC++ permitiendo el uso código nativo C++ en Swift y viceversa con muy poco esfuerzo.
La interoperabilidad de C++ está evolucionando activamente, con algunos aspectos sujetos a cambios en futuras versiones a medida que la comunidad recopile comentarios sobre la adopción en el mundo real en bases de código mixtas de Swift y C++.
Para obtener información sobre cómo habilitar la interoperabilidad de C++ y el subconjunto de idiomas admitidos, consulte la documentación.
Nueva Macro para marcar clases como ObservableObject
Con el nuevo sistema de Macros expresivas en Swift 5.9 ahora podemos marcar clases como conformen al protocolo Observable con solo una sola palabra: @Observable. Esto hace automáticamente todas las propiedades de la clases como públicas pudiendo reaccionar luego a los cambios de estado. Veamos un ejemplo sencillo:
import SwiftUI
final class Yorjan : ObservableObject {
var name : String
var edad : Int
init(name: String, edad: Int) {
self.name = name
self.edad = 10
}
}
struct vista : View {
private var nombre : Yorjan = Yorjan(name: "Yorjandis", edad: 25)
var body: some View {
VStack{
Text(nombre.name)
Button("OK"){
nombre.name = "juancito"
}
}
}
}
Muchas otras mejoras se han añadido como el soporte para una mejor detección de errores en Xcode, optimización para operaciones de concurrencia, mejoras en el Swift Package Manager, etc. Podeis ver la lista completa aquí.