@ObservedObject es un Property Wrapper en SwiftUI para observar una instancia de ObservableObject pasada desde el exterior. A diferencia de @StateObject, @ObservedObject no crea un objeto, sino que se suscribe a cambios de uno ya existente. Según la Documentación para Desarrolladores de Apple (2025), @ObservedObject se utiliza en vistas hijo que necesitan rastrear datos que pertenecen al padre. @ObservedObject proporciona una conexión reactiva sin gestionar el ciclo de vida del objeto.
Puntos clave
@ObservedObject es un Property Wrapper que suscribe una vista a los cambios de un ObservableObject. ObservableObject es un protocolo del framework Combine que requiere implementar un publisher objectWillChange. Cuando cualquier propiedad marcada con @Published cambia dentro del ObservedObject, el publisher envía una señal y SwiftUI re-renderiza todas las vistas suscritas a través de @ObservedObject.
La característica principal de @ObservedObject es la ausencia de propiedad. La vista no es responsable de crear o destruir el objeto. El objeto se crea en la vista padre (mediante @StateObject) o se inyecta a través de @EnvironmentObject. La vista hijo solo observa los cambios y recibe actualizaciones. Si el objeto se reemplaza en el padre, @ObservedObject cambia a la nueva instancia.
@ObservedObject es adecuado para escenarios de compartición de datos: modelo de usuario, configuraciones comunes, estado de conexión al servidor. Cuando varias vistas en diferentes niveles de la jerarquía necesitan mostrar los mismos datos, @ObservedObject en cada vista crea suscripciones independientes pero consistentes a una única fuente.
La diferencia entre @ObservedObject y @StateObject es uno de los temas más comunes en entrevistas sobre SwiftUI. La regla principal: @StateObject crea y posee el objeto, @ObservedObject observa uno ya existente. Violar esta regla provoca pérdida inesperada de datos o doble inicialización.
| Característica | @StateObject | @ObservedObject |
|---|---|---|
| Creación del objeto | Sí, al inicializar la vista | No, recibe uno ya creado |
| Propiedad | Vista actual | Componente padre |
| Instancia única | Sí, durante todo el ciclo de vida | No, puede ser reemplazada |
| Recreación al renderizar | No, persiste | Depende del padre |
| Dónde usar | Vista raíz propietaria | Vistas hijo |
@StateObject garantiza que el objeto se crea una vez y sobrevive a inicializaciones repetidas de la estructura de la vista. @ObservedObject recibe el objeto desde el exterior y se recrea con cada inicialización de la estructura padre. Si el padre usa @StateObject para el objeto, las vistas hijo pueden usar @ObservedObject de forma segura: el objeto será único en toda la jerarquía.
El mecanismo de rastreo de @ObservedObject se basa en Combine y el protocolo ObservableObject. Durante la inicialización, SwiftUI llama al publisher objectWillChange: el objeto debe emitir una señal antes de cambiar una propiedad @Published. Combine pasa la señal al grafo de dependencias de SwiftUI, que marca todas las vistas dependientes como necesitadas de actualización. Esto ocurre sincrónicamente antes de que el valor cambie.
class WeatherService: ObservableObject {
@Published var temperature: Double = 22.0
@Published var city: String = "Moscow"
}
struct WeatherView: View {
@ObservedObject var weather: WeatherService
var body: some View {
VStack {
Text("\(weather.city)")
Text("\(weather.temperature)°C")
}
}
}
En el listado WeatherService es un ObservableObject con dos propiedades @Published. WeatherView declara @ObservedObject var weather: WeatherService, recibiendo la instancia del padre. Cuando temperature cambia, objectWillChange se dispara antes de establecer el nuevo valor, SwiftUI re-renderiza WeatherView y se muestra la temperatura actual. La suscripción es gestionada automáticamente por SwiftUI: el desarrollador no necesita llamar a sink ni dispose.
El primer patrón es pasar un modelo a través del inicializador. El padre crea un ObservableObject mediante @StateObject y lo pasa a las vistas hijo como @ObservedObject. Esta es una transferencia jerárquica estándar de datos donde la vista raíz gestiona el ciclo de vida del modelo y todos los componentes anidados se suscriben a los cambios.
El segundo patrón es EnvironmentObject, una versión global de @ObservedObject a través del entorno de SwiftUI. El objeto se inyecta a nivel de escena o vista raíz y está disponible automáticamente para todos los componentes hijo sin necesidad de pasarlo explícitamente por inicializadores. Dentro de la vista hijo, @EnvironmentObject funciona de manera similar a @ObservedObject pero recibe el objeto del entorno.
El tercer patrón es la composición de múltiples ObservableObject. En aplicaciones complejas, una vista puede observar varios objetos: @ObservedObject var user: UserService, @ObservedObject var network: NetworkMonitor. Esto separa responsabilidades entre servicios y mantiene la testabilidad de cada componente.
struct DashboardView: View {
@ObservedObject var user: UserViewModel
@ObservedObject var network: NetworkMonitor
var body: some View {
VStack {
Text("Welcome, \(user.name)")
HStack {
Circle()
.fill(network.isConnected ? Color.green : Color.red)
.frame(width: 10, height: 10)
}
}
}
}
DashboardView observa UserViewModel y NetworkMonitor. Cada objeto maneja su propio dominio de datos y notifica independientemente a la vista sobre los cambios. Si la red se desconecta, NetworkMonitor cambia isConnected y SwiftUI re-renderiza DashboardView, actualizando el color del indicador. La composición de ObservableObject es la forma preferida de organizar datos en aplicaciones SwiftUI.
@Published es un Property Wrapper de Combine que añade automáticamente un publisher a una propiedad dentro de ObservableObject. Cuando una propiedad @Published cambia, Combine genera un evento a través del publisher objectWillChange. SwiftUI se suscribe a este publisher al usar @ObservedObject o @StateObject y re-renderiza la vista con cada nuevo valor.
@Published soporta todos los tipos, incluyendo opcionales, colecciones y estructuras personalizadas. Sin embargo, para colecciones (arrays, diccionarios), SwiftUI solo rastrea el reemplazo de la referencia, no la mutación del contenido. Para detectar la adición o eliminación de un elemento, es necesario reasignar la colección completa o usar ObservableObject con objectWillChange.send() manual.
Un detalle importante: @Published debe usarse solo dentro de una clase que implemente ObservableObject. Usar @Published fuera de ObservableObject causará un error de compilación. Además, @Published no se puede aplicar a propiedades de inicialización perezosa (lazy var) ni a propiedades calculadas.
El error más crítico es usar @ObservedObject para crear un objeto. Si escribes @ObservedObject var model = UserViewModel() en la vista padre, cada renderizado creará una nueva instancia de UserViewModel. Los datos se perderán y las suscripciones @Published se recrearán. Usa siempre @StateObject para la creación y @ObservedObject solo para recibir un objeto ya creado.
El segundo error es modificar propiedades @Published fuera del hilo principal. ObservableObject usa Combine, que requiere enviar cambios en el hilo principal (main actor). Si cambias @Published en una cola en segundo plano, SwiftUI podría re-renderizar la vista en un momento inadecuado, causando condiciones de carrera. Usa DispatchQueue.main.async o @MainActor para las actualizaciones.
El tercer problema son las actualizaciones cíclicas. Si un cambio de @Published desencadena efectos secundarios que vuelven a cambiar @Published, se produce un bucle infinito de re-renderizados. La solución: usar banderas de protección (isUpdating) o separar la lógica en diferentes ObservableObject con límites de responsabilidad claros.
Preguntas frecuentes
Sí, SwiftUI soporta @ObservedObject var model: UserViewModel?. Sin embargo, la vista no se suscribirá a cambios mientras el objeto sea nil. Cuando se asigna un valor, la suscripción se activa automáticamente.
@ObservedObject recibe el objeto a través del inicializador, @EnvironmentObject a través del entorno de SwiftUI. @EnvironmentObject no requiere pasar explícitamente por constructores, pero el objeto debe inyectarse en el nivel superior de la jerarquía.
Llama a objectWillChange.send() antes de cambiar la propiedad. Esto es útil cuando @Published no es adecuado (por ejemplo, para propiedades calculadas u operaciones con colecciones donde necesitas informar del cambio antes de la mutación).
@ObservedObject y @Published rastrean el reemplazo de la referencia, no la mutación del contenido de la colección. Para provocar un re-renderizado, necesitas reasignar el array: items.append(newItem) → items = items o usar objectWillChange.send() antes de la mutación.
No, @ObservedObject es un Property Wrapper de SwiftUI disponible solo dentro de tipos que implementan el protocolo View. Para estructuras normales, usa Combine directamente con ObservableObjectPublisher.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también