@ObservedObject é um property wrapper em SwiftUI que permite a uma View observar alterações em um ObservableObject criado em outro lugar da hierarquia. Diferente de @StateObject, @ObservedObject não cria o objeto — ele apenas se inscreve no publisher objectWillChange e redesenha a View quando propriedades publicadas são atualizadas. Isso torna @ObservedObject a escolha certa para Views filhas que recebem dados de um pai através de um inicializador. De acordo com um artigo de Paul Hudson — Hacking with Swift (2025), uma arquitetura típica de aplicação SwiftUI é construída assim: a View raiz usa @StateObject para criar um view model, e todas as Views filhas o recebem através de @ObservedObject, garantindo uma única fonte de verdade sem duplicação de dados.
Pontos principais
@ObservedObject é um property wrapper que inscreve uma View em mudanças ObservableObject. Quando um objeto marcado com @ObservedObject altera qualquer uma de suas propriedades declaradas com @Published, o SwiftUI redesenha automaticamente a View. @ObservedObject não cria o objeto — ele apenas estabelece uma conexão entre uma instância ObservableObject existente e a View que deve reagir às suas mudanças.
A diferença chave entre @ObservedObject e @StateObject é a propriedade. @ObservedObject assume que o objeto foi criado e armazenado em algum lugar mais alto na hierarquia de Views. A View filha recebe uma referência a este objeto através do inicializador e simplesmente o observa. Se a View filha for recriada, ela recebe a mesma referência do pai — os dados não se perdem.
De acordo com a Apple Developer Documentation — SwiftUI (2025), @ObservedObject está disponível desde o iOS 13, tornando-o a única opção para observar ObservableObject em projetos que suportam versões antigas do iOS. No iOS 14+, @StateObject é preferível para criar objetos, mas @ObservedObject continua relevante para passar objetos existentes.
O mecanismo do @ObservedObject é baseado no protocolo ObservableObject do framework Combine. Cada classe em conformidade com ObservableObject obtém automaticamente um publisher objectWillChange que envia um sinal antes de qualquer alteração em propriedades @Published. O SwiftUI se inscreve neste publisher através de @ObservedObject e, ao receber o sinal, marca a View como necessitando redesenho.
class TaskViewModel: ObservableObject {
@Published var tasks: [Task] = []
@Published var isLoading = false
func loadTasks() async {
isLoading = true
// buscar dados
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() }
}
}
Quando a View pai passa viewModel para TaskListView através do inicializador, o SwiftUI cria uma conexão entre o objeto e a View. Quando o array tasks ou a flag isLoading mudam, o SwiftUI redesenha TaskListView. O objeto em si permanece inalterado — ele é armazenado na View pai através de @StateObject.
A diferença entre @ObservedObject e @StateObject é a diferença entre um observador e um proprietário. @StateObject cria o objeto e gerencia seu ciclo de vida. @ObservedObject apenas observa um objeto que foi criado e armazenado em outro lugar. A escolha entre eles é determinada pela responsabilidade da View sobre os dados.
| Cenário | Recomendação | Motivo |
|---|---|---|
| View cria dados | @StateObject | View possui o objeto e é responsável pelo seu ciclo de vida |
| View recebe dados | @ObservedObject | View apenas observa, o objeto vive no pai |
| Suporte iOS 13 | @ObservedObject | @StateObject indisponível, use @ObservedObject com gerenciamento manual |
| Componente reutilizável | @ObservedObject | Componente não deve criar dados — ele os recebe externamente |
A regra principal: se a View cria o objeto — @StateObject. Se a View recebe o objeto — @ObservedObject. Violar esta regra usando @ObservedObject para criar um objeto leva à perda de dados quando a View é reconstruída. Violá-la usando @StateObject para receber um objeto cria uma instância duplicada independente do pai.
Um cenário típico de uso do @ObservedObject é uma lista de tarefas onde a View raiz cria um view model e cada célula da lista o recebe através de @ObservedObject. Cada célula pode chamar métodos do view model, e as mudanças são refletidas automaticamente em toda a lista, já que todas as células observam o mesmo objeto.
struct TaskRow: View {
@ObservedObject var viewModel: TaskViewModel
let task: Task
var body: some View {
HStack {
Text(task.title)
Spacer()
Button("Concluído") {
viewModel.completeTask(task)
}
}
}
}
struct TaskListContainer: View {
@StateObject var viewModel = TaskViewModel()
var body: some View {
List(viewModel.tasks) { task in
TaskRow(viewModel: viewModel, task: task)
}
}
}
Neste exemplo, TaskListContainer cria viewModel através de @StateObject, e cada TaskRow o recebe através de @ObservedObject. Quando o usuário pressiona “Done” em qualquer linha, viewModel.completeTask altera uma propriedade publicada, e todas as Views que observam este objeto são atualizadas automaticamente.
O erro mais comum é usar @ObservedObject para criar um objeto dentro de uma View. Quando a View é reconstruída (por exemplo, quando o estado muda), o SwiftUI cria uma nova instância ObservableObject, levando à perda de todos os dados acumulados. Este erro é especialmente doloroso no NavigationStack, onde um usuário pode preencher um formulário e perder os dados ao navegar de volta.
// ❌ Perda de dados: @ObservedObject não retém o objeto
struct FormView: View {
@ObservedObject var formVM = FormViewModel()
// Novo formVM criado em cada reconstrução de View!
}
// ✅ Correto: @StateObject retém o objeto
struct FormView: View {
@StateObject var formVM = FormViewModel()
// Objeto criado uma vez por vida útil da View
}
Se uma View filha declara o mesmo ObservableObject através de @StateObject, ela cria uma cópia independente. Alterações no objeto pai não serão visíveis na filha, e vice-versa. Sempre use @ObservedObject para Views filhas que recebem o objeto externamente.
No SwiftUI moderno existem várias alternativas ao @ObservedObject, cada uma com suas vantagens. A escolha depende da arquitetura da aplicação, da versão do iOS e do caso de uso específico.
A escolha entre @ObservedObject e @EnvironmentObject é uma questão de estilo e arquitetura. @ObservedObject mostra explicitamente as dependências da View através do inicializador, tornando o código mais previsível. @EnvironmentObject é conveniente para hierarquias profundas, mas esconde dependências, o que pode dificultar a depuração.
Perguntas frequentes
Sim, se o objeto for criado e armazenado fora do SwiftUI — por exemplo, em um AppDelegate ou singleton. Neste caso, @ObservedObject simplesmente se inscreve nas mudanças de um objeto existente. No entanto, para objetos criados dentro da hierarquia SwiftUI, @StateObject é sempre necessário em algum nível superior.
A razão mais provável é que a propriedade é alterada não através de @Published ou o objeto em si não é alterado, mas sua estrutura interna sofre mutação sem chamar objectWillChange. Para coleções, use atribuição de uma nova cópia: array.append() não é suficiente — você precisa reatribuir o próprio array através de array = array + [element].
@ObservedObject por si só não cria sobrecarga significativa. Os problemas surgem com alterações frequentes de propriedades @Published — cada mudança dispara um redesenho de todas as Views observadoras. Para otimizar, use EquatableView, reduza o número de propriedades publicadas e evite atualizações desnecessárias.
@ObservedObject observa uma classe ObservableObject inteira e redesenha a View em qualquer alteração em suas propriedades publicadas. @Binding cria uma conexão bidirecional com um valor específico (String, Int, Bool) e permite lê-lo e escrevê-lo. @Binding é mais leve e não requer ObservableObject.
Sim, este é o padrão normal. @Published dentro de ObservableObject integra-se automaticamente com @ObservedObject. Cada propriedade @Published adiciona um observador ao publisher objectWillChange. Quando qualquer uma delas muda, todas as Views com @ObservedObject para este objeto são redesenhadas.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também