@ObservedObject é um Property Wrapper no SwiftUI para observar uma instância de ObservableObject passada externamente. Ao contrário de @StateObject, @ObservedObject não cria um objeto — ele se inscreve nas mudanças de um já existente. De acordo com a Documentação para Desenvolvedores Apple (2025), @ObservedObject é usado em view filhas que precisam rastrear dados pertencentes ao pai. @ObservedObject fornece uma conexão reativa sem gerenciar o ciclo de vida do objeto.
Principais pontos
@ObservedObject é um Property Wrapper que inscreve uma view nas mudanças de um ObservableObject. ObservableObject é um protocolo do framework Combine que requer a implementação de um publisher objectWillChange. Quando qualquer propriedade marcada com @Published muda dentro do ObservedObject, o publisher envia um sinal e o SwiftUI re-renderiza todas as views inscritas através de @ObservedObject.
A principal característica do @ObservedObject é a ausência de propriedade. A view não é responsável por criar ou destruir o objeto. O objeto é criado na view pai (via @StateObject) ou injetado através de @EnvironmentObject. A view filha apenas observa as mudanças e recebe atualizações. Se o objeto for substituído no pai, @ObservedObject muda para a nova instância.
@ObservedObject é adequado para cenários de compartilhamento de dados: modelo de usuário, configurações comuns, estado de conexão com o servidor. Quando várias views em diferentes níveis hierárquicos precisam exibir os mesmos dados, @ObservedObject em cada view cria assinaturas independentes mas consistentes para uma única fonte.
A diferença entre @ObservedObject e @StateObject é um dos tópicos mais comuns em entrevistas sobre SwiftUI. A regra principal: @StateObject cria e possui o objeto, @ObservedObject observa um já existente. Violar essa regra leva à perda inesperada de dados ou inicialização dupla.
| Característica | @StateObject | @ObservedObject |
|---|---|---|
| Criação do objeto | Sim, na inicialização da view | Não, recebe um já pronto |
| Propriedade | View atual | Componente pai |
| Instância única | Sim, por todo o ciclo de vida | Não, pode ser substituída |
| Recriação ao renderizar | Não, persiste | Depende do pai |
| Onde usar | View raiz proprietária | Views filhas |
@StateObject garante que o objeto é criado uma vez e sobrevive a inicializações repetidas da estrutura da view. @ObservedObject recebe o objeto externamente e é recriado a cada inicialização da estrutura pai. Se o pai usa @StateObject para o objeto, as views filhas podem usar @ObservedObject com segurança — o objeto será único em toda a hierarquia.
O mecanismo de rastreamento do @ObservedObject é baseado no Combine e no protocolo ObservableObject. Durante a inicialização, o SwiftUI chama o publisher objectWillChange — o objeto deve emitir um sinal antes de alterar uma propriedade @Published. O Combine passa o sinal para o grafo de dependências do SwiftUI, que marca todas as views dependentes como precisando de atualização. Isso acontece sincronamente antes do valor ser alterado.
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")
}
}
}
No exemplo WeatherService é um ObservableObject com duas propriedades @Published. WeatherView declara @ObservedObject var weather: WeatherService, recebendo a instância do pai. Quando temperature muda, objectWillChange é disparado antes de definir o novo valor, o SwiftUI re-renderiza WeatherView e a temperatura atual é exibida. A assinatura é gerenciada automaticamente pelo SwiftUI — o desenvolvedor não precisa chamar sink ou dispose.
O primeiro padrão é passar um modelo pelo inicializador. O pai cria um ObservableObject via @StateObject e o passa para as views filhas como @ObservedObject. Esta é uma transferência hierárquica padrão de dados onde a view raiz gerencia o ciclo de vida do modelo e todos os componentes aninhados se inscrevem nas mudanças.
O segundo padrão é EnvironmentObject, uma versão global do @ObservedObject através do ambiente SwiftUI. O objeto é injetado no nível da cena ou view raiz e fica automaticamente disponível para todos os componentes filhos sem passagem explícita por inicializadores. Dentro da view filha, @EnvironmentObject funciona de forma similar ao @ObservedObject mas recebe o objeto do ambiente.
O terceiro padrão é a composição de múltiplos ObservableObject. Em aplicações complexas, uma view pode observar vários objetos: @ObservedObject var user: UserService, @ObservedObject var network: NetworkMonitor. Isso separa responsabilidades entre serviços e mantém a testabilidade 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 e NetworkMonitor. Cada objeto lida com seu próprio domínio de dados e notifica a view independentemente sobre mudanças. Se a rede desconectar, NetworkMonitor altera isConnected e o SwiftUI re-renderiza DashboardView, atualizando a cor do indicador. A composição de ObservableObject é a forma preferida de organizar dados em aplicações SwiftUI.
@Published é um Property Wrapper do Combine que adiciona automaticamente um publisher a uma propriedade dentro de ObservableObject. Quando uma propriedade @Published muda, o Combine gera um evento através do publisher objectWillChange. O SwiftUI se inscreve neste publisher ao usar @ObservedObject ou @StateObject e re-renderiza a view a cada novo valor.
@Published suporta todos os tipos, incluindo opcionais, coleções e estruturas personalizadas. No entanto, para coleções (arrays, dicionários), o SwiftUI rastreia apenas a substituição da referência, não a mutação do conteúdo. Para detectar adição ou remoção de elementos, é necessário reatribuir a coleção inteira ou usar ObservableObject com objectWillChange.send() manual.
Um detalhe importante: @Published deve ser usado apenas dentro de uma classe que implementa ObservableObject. Usar @Published fora de ObservableObject causará um erro de compilação. Além disso, @Published não pode ser aplicado a propriedades de inicialização preguiçosa (lazy var) ou propriedades computadas.
O erro mais crítico é usar @ObservedObject para criar um objeto. Se você escrever @ObservedObject var model = UserViewModel() na view pai, cada renderização criará uma nova instância de UserViewModel. Os dados serão perdidos e as assinaturas @Published serão recriadas. Use sempre @StateObject para criação e @ObservedObject apenas para receber um objeto já pronto.
O segundo erro é modificar propriedades @Published fora da thread principal. ObservableObject usa Combine, que requer o envio de mudanças na thread principal (main actor). Se você alterar @Published em uma fila de fundo, o SwiftUI pode re-renderizar a view em um momento inadequado, causando condições de corrida. Use DispatchQueue.main.async ou @MainActor para atualizações.
O terceiro problema são as atualizações cíclicas. Se uma mudança @Published desencadeia efeitos colaterais que novamente alteram @Published, ocorre um loop infinito de re-renderização. A solução: usar flags de proteção (isUpdating) ou separar a lógica em diferentes ObservableObject com limites de responsabilidade claros.
Perguntas frequentes
Sim, o SwiftUI suporta @ObservedObject var model: UserViewModel?. No entanto, a view não será inscrita em mudanças enquanto o objeto for nil. Quando um valor é atribuído, a assinatura é ativada automaticamente.
@ObservedObject recebe o objeto através do inicializador, @EnvironmentObject através do ambiente SwiftUI. @EnvironmentObject não requer passagem explícita por construtores, mas o objeto deve ser injetado no nível superior da hierarquia.
Chame objectWillChange.send() antes de alterar a propriedade. Isso é útil quando @Published não é adequado (por exemplo, para propriedades computadas ou operações com coleções onde você precisa relatar a mudança antes da mutação).
@ObservedObject e @Published rastreiam a substituição da referência, não a mutação do conteúdo da coleção. Para acionar uma re-renderização, você precisa reatribuir o array: items.append(newItem) → items = items ou usar objectWillChange.send() antes da mutação.
Não, @ObservedObject é um Property Wrapper do SwiftUI disponível apenas dentro de tipos que implementam o protocolo View. Para structs comuns, use Combine diretamente com ObservableObjectPublisher.
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