@EnvironmentObject é um property wrapper no SwiftUI que permite que qualquer View na hierarquia acesse um ObservableObject sem passá-lo explicitamente por uma cadeia de inicializadores. O objeto é injetado no ambiente usando o modificador .environmentObject() em um nível específico da hierarquia, após o qual todas as Views filhas podem acessá-lo via @EnvironmentObject. Isso elimina a necessidade de passar o objeto por Views intermediárias que não o utilizam — o chamado prop drilling. De acordo com um artigo de John Sundell — Swift by Sundell (2025), @EnvironmentObject é especialmente útil para dados entre telas: sessão do usuário, configurações do aplicativo, gerenciador de carrinho de compras ou cache local de dados.
Pontos principais
@EnvironmentObject é um property wrapper que permite que Views do SwiftUI acessem um ObservableObject a partir do ambiente do aplicativo. O ambiente é um contêiner no qual objetos podem ser colocados em qualquer nível da hierarquia de View usando o modificador .environmentObject(). Uma vez que um objeto é colocado no ambiente, qualquer View filha pode acessá-lo simplesmente declarando uma propriedade com @EnvironmentObject e especificando o tipo do objeto.
O objetivo principal do @EnvironmentObject é resolver o problema de passar dados através de uma hierarquia profunda de Views sem ter que passar o objeto por cada nível intermediário. Em aplicativos complexos com NavigationStack, TabView e janelas modais ramificadas, @EnvironmentObject simplifica significativamente a arquitetura ao eliminar código boilerplate.
De acordo com Apple Developer Documentation — Environment (2025), @EnvironmentObject usa um mecanismo interno do SwiftUI baseado em PreferenceKey e identificação de View. Cada View armazena uma referência ao seu próprio ambiente, que é herdado da View pai e pode ser estendido usando .environmentObject(). A busca pelo objeto sobe pela hierarquia até a View raiz.
class UserSession: ObservableObject {
@Published var isLoggedIn = false
@Published var userName: String = ""
func login(name: String) {
userName = name
isLoggedIn = true
}
}
@main
struct MyApp: App {
@StateObject var session = UserSession()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(session)
}
}
}
@EnvironmentObject funciona com base em um mecanismo de injeção de dependência (DI) embutido no SwiftUI. Quando você chama .environmentObject() em uma View, o SwiftUI armazena o objeto em um armazenamento especial associado a essa View e todos os seus descendentes. Quando uma View filha declara @EnvironmentObject do mesmo tipo, o SwiftUI procura o objeto no ambiente, subindo pela hierarquia de pais.
Uma característica importante — o tipo do objeto é usado como chave para a busca no ambiente. Se houver dois objetos do mesmo tipo no ambiente, o SwiftUI encontra o mais próximo da View atual na hierarquia. Quando o objeto é injetado no nível WindowGroup, ele se torna globalmente disponível para todas as telas do aplicativo, o que é conveniente para serviços de uso geral.
De acordo com objc.io — SwiftUI Architecture (2025), internamente @EnvironmentObject usa um mecanismo semelhante ao @ObservedObject, mas com uma camada adicional de abstração para encontrar o objeto na hierarquia. O SwiftUI não copia o objeto nem cria um novo — ele passa uma referência à instância existente, de modo que as alterações no objeto são automaticamente visíveis para todas as Views que usam @EnvironmentObject.
Tanto @EnvironmentObject quanto @ObservedObject realizam a mesma função básica — eles inscrevem uma View em alterações em um ObservableObject. A diferença está no mecanismo de passagem do objeto. @ObservedObject requer passagem explícita através de um inicializador, enquanto @EnvironmentObject recupera o objeto do ambiente sem especificação explícita em cada View intermediária.
| Característica | @EnvironmentObject | @ObservedObject |
|---|---|---|
| Passagem | Via .environmentObject() no nível da hierarquia | Através do inicializador de cada View |
| Visibilidade de dependências | Oculta — não visível na assinatura da View | Explícita — visível no init da View |
| Views intermediárias | Não sabem sobre o objeto | Devem passar o objeto adiante |
| Risco de erro | Falha em tempo de execução quando o objeto está ausente | Verificação em tempo de compilação (se o parâmetro for obrigatório) |
| Prop drilling | Elimina | Requer passagem manual |
A escolha entre @EnvironmentObject e @ObservedObject depende da arquitetura. Se o objeto for necessário no fundo da hierarquia e em muitas telas — @EnvironmentObject é mais conveniente. Se a arquitetura exigir especificação explícita de dependências para teste e legibilidade — @ObservedObject é preferível.
O cenário mais comum é uma sessão de usuário que precisa estar acessível em todas as telas do aplicativo. Ao injetar UserSession via .environmentObject() na raiz do aplicativo, qualquer tela pode acessar os dados do usuário e o status de autorização.
struct ProfileView: View {
@EnvironmentObject var session: UserSession
var body: some View {
VStack {
if session.isLoggedIn {
Text("Hello, \(session.userName)")
Button("Logout") {
session.isLoggedIn = false
}
} else {
LoginView()
}
}
}
}
struct SettingsView: View {
@EnvironmentObject var session: UserSession
var body: some View {
Form {
Text("Logged in as \(session.userName)")
}
}
}
Observe que nem ProfileView nem SettingsView recebem a sessão através de um inicializador. Eles simplesmente declaram @EnvironmentObject var session: UserSession, e o SwiftUI encontra automaticamente o objeto no ambiente. Isso permite adicionar novas telas sem alterar o código existente de transferência de dados.
O principal risco do @EnvironmentObject é uma falha em tempo de execução se o objeto não tiver sido injetado no ambiente. Ao contrário de parâmetros opcionais, @EnvironmentObject não pode ser nil. Se uma View com @EnvironmentObject aparecer na tela e a View pai não tiver chamado .environmentObject() para esse tipo, o aplicativo falha imediatamente com “Fatal error: No ObservableObject of type X found”.
Se você injetar dois objetos do mesmo tipo em diferentes níveis da hierarquia, a View filha receberá o mais próximo pela hierarquia. Isso pode causar confusão se o desenvolvedor esperar que o objeto do ambiente raiz esteja disponível em uma janela modal que tem seu próprio ambiente com um objeto do mesmo tipo.
Com a evolução do SwiftUI, surgiram abordagens alternativas de gerenciamento de dependências que resolvem algumas deficiências do @EnvironmentObject — principalmente a implicitude das dependências e o risco de falhas em tempo de execução.
A escolha da abordagem depende do tamanho da equipe e da complexidade do aplicativo. Para projetos pequenos, @EnvironmentObject funciona muito bem. Para projetos grandes com dezenas de telas e requisitos rigorosos de teste, a passagem explícita via @ObservedObject ou um contêiner DI é preferível.
Perguntas frequentes
Sim, uma View pode declarar quantos @EnvironmentObject de diferentes tipos precisar. O SwiftUI procura cada tipo independentemente no ambiente. Isso é útil quando uma View precisa acessar a sessão do usuário, as configurações e o carrinho de compras simultaneamente — cada objeto é injetado separadamente.
O Preview falha com um erro em tempo de execução ao tentar exibir a View. Sempre adicione .environmentObject() no Preview para Views que usam @EnvironmentObject. Use objetos simulados com dados de teste para que o Preview funcione corretamente e mostre um estado realista.
Não, @EnvironmentObject funciona apenas com um tipo de classe concreta que esteja em conformidade com ObservableObject. Para protocolos, você precisa usar type erasure ou um invólucro: crie uma classe invólucro que contenha uma referência ao objeto de tipo de protocolo e injete o invólucro via @EnvironmentObject.
Crie uma instância de ObservableObject com dados de teste e passe-a para a View via .environmentObject(testObject) no teste. Este é o padrão padrão para testes de UI em SwiftUI. Para testes unitários, isole a lógica no ObservableObject e teste-o separadamente da View.
@EnvironmentObject não cria carga adicional de desempenho porque ele apenas passa uma referência para o objeto, não uma cópia. No entanto, atualizações frequentes de propriedades @Published em um objeto global podem fazer com que muitas Views sejam redesenhadas simultaneamente, o que pode afetar o desempenho.
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