@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
@Observable
class 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.
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) |
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.
- 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.