@Observable y el estado compartido
El framework Observation reemplaza a ObservableObject: clases reactivas con la macro @Observable, sin @Published ni boilerplate. El corazón del estado moderno en SwiftUI.
@State es genial para datos locales, pero las apps reales necesitan modelos compartidos entre muchas vistas: un carrito, la sesión del usuario, los ajustes. Para eso llegó el framework Observation con la macro @Observable: reactividad sin ceremonia.
- La macro
@Observabley qué genera. - Usar un modelo observable en las vistas.
@Bindablepara bindings a sus propiedades.- Por qué reemplazó a
ObservableObject.
El modelo observable
Marca una clase con @Observable y SwiftUI observará automáticamente cualquier propiedad que uses en una vista:
import Observation@Observableclass CarritoModel { var items: [String] = [] var total = 0.0 func añadir(_ item: String, precio: Double) { items.append(item) total += precio }}Sin @Published, sin objectWillChange, sin nada. SwiftUI detecta qué propiedades lee cada vista y solo la redibuja cuando esas cambian.
Usarlo en una vista
La vista que “posee” el modelo lo guarda en @State (sí, @State también sirve para objetos observables):
struct TiendaView: View { @State private var carrito = CarritoModel() var body: some View { VStack { Text("Total: \(carrito.total, format: .currency(code: "EUR"))") Button("Añadir café") { carrito.añadir("Café", precio: 1.5) } } }}Cambias carrito.total desde el método y la vista se actualiza sola.
Observación granular = rendimiento
La magia de @Observable: SwiftUI rastrea qué propiedades lee de verdad cada vista. Si una vista solo muestra carrito.total, cambiar carrito.items no la redibuja. Con el viejo ObservableObject + @Published, cualquier cambio en el objeto redibujaba todo lo suscrito. Ahora la actualización es quirúrgica: solo se recalcula lo que depende del dato que cambió. Modelos grandes sin penalización de rendimiento.
@Bindable: bindings a un modelo
¿Necesitas un TextField o Toggle conectado a una propiedad del modelo? @Bindable te da los $bindings:
struct AjustesView: View { @Bindable var ajustes: AjustesModel var body: some View { Form { TextField("Nombre", text: $ajustes.nombre) // $ del modelo Toggle("Modo oscuro", isOn: $ajustes.oscuro) } }}@Bindable es el puente entre un objeto @Observable y los controles que piden un Binding.
Adiós a ObservableObject
Si ves código con class X: ObservableObject, @Published var, @StateObject y @ObservedObject, es el sistema anterior. La tabla de equivalencias:
| Antiguo | Moderno (Observation) |
|---|---|
class: ObservableObject |
@Observable class |
@Published var |
var (normal) |
@StateObject var |
@State var |
@ObservedObject var |
var o @Bindable var |
@EnvironmentObject |
@Environment(Modelo.self) |
Empieza siempre con @Observable
Para cualquier proyecto nuevo con iOS 17+, usa @Observable desde el principio: menos código, mejor rendimiento y es el camino que Apple recomienda. El sistema antiguo solo lo verás en código heredado. La comunicación entre vistas mediante @Environment la ves en la próxima lección.
Comparte estado de verdad
- Crea una clase
@Observablecon una propiedad y un método que la cambie. - Posee el modelo en una vista con
@State private var. - Muestra una propiedad y un botón que llame al método; observa la actualización.
- Crea otra vista con
@Bindabley conecta unTextFielda$modelo.propiedad.