@ObservedObject es un property wrapper en SwiftUI que permite a una View observar cambios en un ObservableObject creado en otro lugar de la jerarquía. A diferencia de @StateObject, @ObservedObject no crea el objeto — solo se suscribe a su publisher objectWillChange y redibuja la View cuando se actualizan las propiedades publicadas. Esto hace que @ObservedObject sea la opción correcta para Views hijas que reciben datos de un padre a través de un inicializador. Según un artículo de Paul Hudson — Hacking with Swift (2025), una arquitectura típica de aplicación SwiftUI se construye así: la View raíz usa @StateObject para crear un view model, y todas las Views hijas lo reciben a través de @ObservedObject, garantizando una única fuente de verdad sin duplicación de datos.
Puntos clave
@ObservedObject es un property wrapper que suscribe una View a los cambios de ObservableObject. Cuando un objeto marcado con @ObservedObject cambia alguna de sus propiedades declaradas con @Published, SwiftUI redibuja automáticamente la View. @ObservedObject no crea el objeto — solo establece una conexión entre una instancia existente de ObservableObject y la View que debe reaccionar a sus cambios.
La diferencia clave entre @ObservedObject y @StateObject es la propiedad. @ObservedObject asume que el objeto se crea y almacena en algún lugar más arriba en la jerarquía de Views. La View hija recibe una referencia a este objeto a través del inicializador y simplemente lo observa. Si la View hija se recrea, recibe la misma referencia del padre — los datos no se pierden.
Según Apple Developer Documentation — SwiftUI (2025), @ObservedObject está disponible desde iOS 13, lo que lo convierte en la única opción para observar ObservableObject en proyectos que admiten versiones antiguas de iOS. En iOS 14+ se prefiere @StateObject para crear objetos, pero @ObservedObject sigue siendo relevante para pasar objetos existentes.
El mecanismo de @ObservedObject se basa en el protocolo ObservableObject del framework Combine. Cada clase que conforma ObservableObject obtiene automáticamente un publisher objectWillChange que envía una señal antes de que cualquier propiedad @Published cambie. SwiftUI se suscribe a este publisher a través de @ObservedObject y al recibir la señal marca la View como necesitada de redibujado.
class TaskViewModel: ObservableObject {
@Published var tasks: [Task] = []
@Published var isLoading = false
func loadTasks() async {
isLoading = true
// fetch data
isLoading = false
}
}
struct TaskListView: View {
@ObservedObject var viewModel: TaskViewModel
var body: some View {
List(viewModel.tasks) { task in
Text(task.title)
}
.task { await viewModel.loadTasks() }
}
}
Cuando la View padre pasa viewModel a TaskListView a través del inicializador, SwiftUI crea una conexión entre el objeto y la View. Cuando el array tasks o el flag isLoading cambian, SwiftUI redibuja TaskListView. El objeto en sí permanece sin cambios — se almacena en la View padre a través de @StateObject.
La diferencia entre @ObservedObject y @StateObject es la diferencia entre un observador y un propietario. @StateObject crea el objeto y gestiona su ciclo de vida. @ObservedObject solo observa un objeto que fue creado y almacenado en otro lugar. La elección entre ellos está determinada por la responsabilidad de la View sobre los datos.
| Escenario | Recomendación | Motivo |
|---|---|---|
| La View crea datos | @StateObject | La View posee el objeto y es responsable de su ciclo de vida |
| La View recibe datos | @ObservedObject | La View solo observa, el objeto vive en el padre |
| Soporte iOS 13 | @ObservedObject | @StateObject no está disponible, usa @ObservedObject con gestión manual |
| Componente reutilizable | @ObservedObject | El componente no debe crear datos — los recibe externamente |
La regla principal: si la View crea el objeto — @StateObject. Si la View recibe el objeto — @ObservedObject. Violar esta regla usando @ObservedObject para crear un objeto provoca pérdida de datos cuando la View se reconstruye. Violarla usando @StateObject para recibir un objeto crea una instancia duplicada independiente del padre.
Un escenario típico de uso de @ObservedObject es una lista de tareas donde la View raíz crea un view model y cada celda de la lista lo recibe a través de @ObservedObject. Cada celda puede llamar a métodos del view model, y los cambios se reflejan automáticamente en toda la lista ya que todas las celdas observan el mismo objeto.
struct TaskRow: View {
@ObservedObject var viewModel: TaskViewModel
let task: Task
var body: some View {
HStack {
Text(task.title)
Spacer()
Button("Done") {
viewModel.completeTask(task)
}
}
}
}
struct TaskListContainer: View {
@StateObject var viewModel = TaskViewModel()
var body: some View {
List(viewModel.tasks) { task in
TaskRow(viewModel: viewModel, task: task)
}
}
}
En este ejemplo, TaskListContainer crea viewModel a través de @StateObject, y cada TaskRow lo recibe a través de @ObservedObject. Cuando el usuario presiona “Done” en cualquier fila, viewModel.completeTask cambia una propiedad publicada, y todas las Views que observan este objeto se actualizan automáticamente.
El error más común es usar @ObservedObject para crear un objeto dentro de una View. Cuando la View se reconstruye (por ejemplo, al cambiar el estado), SwiftUI crea una nueva instancia de ObservableObject, lo que provoca la pérdida de todos los datos acumulados. Este error es especialmente doloroso en NavigationStack, donde un usuario podría rellenar un formulario y perder los datos al navegar hacia atrás.
// ❌ Pérdida de datos: @ObservedObject no retiene el objeto
struct FormView: View {
@ObservedObject var formVM = FormViewModel()
// ¡Nuevo formVM creado en cada reconstrucción de View!
}
// ✅ Correcto: @StateObject retiene el objeto
struct FormView: View {
@StateObject var formVM = FormViewModel()
// Objeto creado una vez por ciclo de vida de la View
}
Si una View hija declara el mismo ObservableObject a través de @StateObject, crea una copia independiente. Los cambios en el objeto padre no serán visibles en la hija, y viceversa. Usa siempre @ObservedObject para Views hijas que reciben el objeto externamente.
En SwiftUI moderno existen varias alternativas a @ObservedObject, cada una con sus ventajas. La elección depende de la arquitectura de la aplicación, la versión de iOS y el caso de uso específico.
La elección entre @ObservedObject y @EnvironmentObject es una cuestión de estilo y arquitectura. @ObservedObject muestra explícitamente las dependencias de la View a través del inicializador, haciendo el código más predecible. @EnvironmentObject es conveniente para jerarquías profundas pero oculta las dependencias, lo que puede dificultar la depuración.
Preguntas frecuentes
Sí, si el objeto se crea y almacena fuera de SwiftUI — por ejemplo, en un AppDelegate o singleton. En este caso, @ObservedObject simplemente se suscribe a los cambios de un objeto existente. Sin embargo, para objetos creados dentro de la jerarquía SwiftUI, siempre se necesita @StateObject en algún nivel superior.
La razón más probable es que la propiedad se cambia no a través de @Published o que el objeto en sí no se modifica sino que su estructura interna muta sin llamar a objectWillChange. Para colecciones, usa la asignación de una nueva copia: array.append() no es suficiente — necesitas reasignar el array mediante array = array + [element].
@ObservedObject por sí mismo no genera una sobrecarga significativa. Los problemas surgen con cambios frecuentes de propiedades @Published — cada cambio desencadena un redibujado de todas las Views observadoras. Para optimizar, usa EquatableView, reduce el número de propiedades publicadas y evita actualizaciones innecesarias.
@ObservedObject observa una clase ObservableObject completa y redibuja la View ante cualquier cambio en sus propiedades publicadas. @Binding crea una conexión bidireccional con un valor específico (String, Int, Bool) y permite leerlo y escribirlo. @Binding es más ligero y no requiere ObservableObject.
Sí, este es el patrón estándar. @Published dentro de ObservableObject se integra automáticamente con @ObservedObject. Cada propiedad @Published añade un observador al publisher objectWillChange. Cuando cualquiera de ellas cambia, todas las Views con @ObservedObject para este objeto se redibujan.
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