La macro @Observable en iOS 17

Macro @Observable

Con el lanzamiento de iOS 17, Apple introdujo varias mejoras y herramientas para desarrolladores, entre ellas la nueva macro @Observable. Diseñada para trabajar en conjunto con SwiftUI, esta macro facilita el manejo de estados reactivos al simplificar el código y mejorar la integración con el sistema de vistas declarativas. A continuación, exploraremos qué es @Observable, cómo funciona y por qué es una de las adiciones más interesantes para los desarrolladores de la plataforma Apple.

¿Qué es @Observable?

@Observable es una macro introducida en Swift 5.9 y soportada en iOS 17. Pertenece al nuevo framework Observation y su propósito principal es reemplazar o complementar el uso de @ObservedObject y @StateObject, dos de los pilares fundamentales en la gestión de estados en SwiftUI. Esta macro permite que las propiedades de un modelo sean observables automáticamente sin la necesidad de implementar manualmente el protocolo ObservableObject ni agregar la propiedad @Published.

Anteriormente, para que un modelo fuera observable en SwiftUI, tenías que escribir algo como esto:

				
					import SwiftUI
import Combine

class MiModelo: ObservableObject {
    @Published var contador: Int = 0
}
				
			

Con @Observable, este patrón se simplifica radicalmente:

				
					import SwiftUI

@Observable
class MiModelo {
    var contador: Int = 0
}
				
			
				
					@Observable
class ContadorModelo {
    var valor: Int = 0
}
				
			

Gracias a esta macro, el modelo automáticamente genera el comportamiento necesario para notificar a SwiftUI sobre los cambios en las propiedades.

Ventajas de usar @Observable

1.Menor código repetitivo: No es necesario implementar ObservableObject ni marcar manualmente cada propiedad con @Published.

2.Mayor claridad: El modelo es más fácil de leer y mantener, ya que @Observable abstrae la lógica de notificación de cambios.

3.Integración profunda con SwiftUI: Esta macro está diseñada específicamente para el ecosistema SwiftUI, garantizando una experiencia más fluida al manejar estados y actualizaciones de vistas.

4.Soporte para estructuras (structs): A diferencia de @StateObject o @ObservedObject, que requerían clases, @Observable también puede usarse con estructuras, lo que abre nuevas posibilidades para la arquitectura del código.

Cómo funciona @Observable

La macro @Observable utiliza capacidades avanzadas de Swift para generar automáticamente la implementación necesaria que hace que las propiedades sean observables. Esto incluye:

1.La generación automática del protocolo ObservableObject o su equivalente.

2.Notificaciones de cambios para todas las propiedades marcadas dentro de la clase o estructura.

3.Integración automática con SwiftUI para reaccionar a cambios en la UI.

Ejemplo práctico

Imaginemos que estás construyendo una aplicación de contador con SwiftUI. Con @Observable, el código se ve así:

Vista Principal

				
					import SwiftUI

struct ContadorVista: View {
    @State private var modelo = ContadorModelo()

    var body: some View {
        VStack {
            Text("Valor del contador: \(modelo.valor)")
                .font(.largeTitle)
            
            HStack {
                Button("Incrementar") {
                    modelo.valor += 1
                }
                .padding()

                Button("Reiniciar") {
                    modelo.valor = 0
                }
                .padding()
            }
        }
        .padding()
    }
}
				
			

En este ejemplo:

ContadorModelo es observable automáticamente gracias a la macro @Observable.

•La vista reacciona a los cambios en modelo.valor sin necesidad de declarar @Published ni ObservableObject.

Diferencias con @ObservedObject y @StateObject

Aunque @Observable ofrece una experiencia más simplificada, no necesariamente reemplaza a @ObservedObject o @StateObject. Las principales diferencias son:

Macro/Propiedad

Uso

Persistencia

Modelo de Datos

@ObservedObject

Observa un objeto creado fuera de la vista.

Depende de la instancia que lo contiene.

Clases con ObservableObject.

@StateObject

Maneja el ciclo de vida del objeto dentro de la vista.

Persistente entre actualizaciones de la vista.

Clases con ObservableObject.

@Observable

Simplifica la reactividad para propiedades.

Depende del contexto de uso.

 

Compatibilidad y limitaciones

Aunque @Observable introduce grandes ventajas, tiene algunas consideraciones:

1.Requiere iOS 17 o superior: Al estar basada en Swift 5.9, solo está disponible en las plataformas más recientes.

2.Generación automática: Si necesitas un control más detallado sobre cómo se notifican los cambios, puede que prefieras implementar manualmente ObservableObject.

3.Limitado a SwiftUI: Aunque es posible usarlo fuera de SwiftUI, el principal beneficio se encuentra en la integración con este framework.

 

Consideraciones Adicionales

Existe un caso de uso específico con el uso de framework reactivos como Observation y Combine que consiste en el uso de más de una instancia del mismo tipo observable en nuestro proyectos. 

Supongamos que desamos trabajar con dos instancias de un mismo tipo observable. El enfoque anterior no nos sirve debido a que el modelo interno de estos framework reactivos no diferencias entre instancias del mismo tipo. La solución esta en el uso de claves de diferenciación de instancias con ayuda de la macro @Entry. Veamos un ejemplo para ilustrarlo mejor: 

				
					//El modelo Ahora tiene una extensión donde se especifica las claves para diferentes
//instancias del mismo tipo:
@Observable class Model2 {
    var count : Int = 0
    var text : String = ""
    @ObservationIgnored var notObserved : Bool = false //Not Observed
    
}


extension EnvironmentValues{
    @Entry var primero : Model2 = Model2()
    @Entry var segundo : Model2 = Model2()

}

//----------------------------
import SwiftUI


struct TestScreen : View{
    
    @Environment(\.primero) var model //Instancia 1
    @Environment(\.segundo) var model2 //Instancia 2

    
    var body : some View{
        NavigationStack{
            VStack{
                
                Text("\(String(describing: model.text))")
                Text("\(String(describing: model2.text))")
                Button("OK"){
                    model.text = "Hello"
                    model2.text = "Hello2"
                }
                
            }
        }
        .environment(\.primero, model)
        .environment(\.segundo, model2)
        
    }

}




#Preview {
    TestScreen()
        .environment(Model2())
}

				
			

En este ejemplo, las vistas de texto que reflejan los datos a partir de “model” y “model2” pueden actualizar su contenido por separado. Esto es posible gracias a la separación de instancias con el uso de Key/paths que genera la macro @Entry.

Observe el uso del contenedor environment para especificar la instancia específica que queremos referenciar dentro de la vista.

Conclusión

La macro @Observable es una herramienta poderosa que reduce la complejidad al trabajar con estados y datos reactivos en SwiftUI. Al automatizar la generación del comportamiento observable, los desarrolladores pueden concentrarse más en la lógica de negocio y la experiencia del usuario, en lugar de lidiar con detalles repetitivos.

Si estás desarrollando aplicaciones para iOS 17 o macOS Sonoma o superior, es recomendable reemplazar el protocolo ObservableObject por la macro @Observable como una forma moderna y eficiente de gestionar estados en SwiftUI. 

Si te ha gustado este contenido podeis dejármelo saber en los comentarios. Gracias por leer y feliz codificación!

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Scroll al inicio