@StateObject: o que é, criação e gerenciamento de ObservableObject

Autor: IT Sectr Publicado: 2026-06-26 Tempo de leitura: 9 min

@StateObject é um property wrapper no SwiftUI que cria e possui uma instância de ObservableObject durante todo o ciclo de vida de uma View. Quando uma View aparece pela primeira vez na tela, @StateObject inicializa o objeto e o armazena até que a View seja removida da memória. Isso garante que os dados não sejam redefinidos ao reconstruir a interface — por exemplo, ao alterar o tema ou atualizar a View pai. De acordo com a Documentação do Desenvolvedor Apple (2025), @StateObject deve ser usado como a fonte primária de verdade (source of truth) para ObservableObject na hierarquia do SwiftUI, enquanto as Views filhas recebem o objeto já criado através de @ObservedObject ou @EnvironmentObject.

Pontos Principais

  • @StateObject é um property wrapper para criar e possuir um ObservableObject dentro de uma View.
  • Criação única — o objeto é inicializado uma vez durante a vida da View e não é recriado nas reconstruções.
  • Fonte de verdade — @StateObject é a fonte de verdade na hierarquia, ao contrário de @ObservedObject.
  • Ciclo de vida — o objeto vive enquanto a View existe na memória e é destruído junto com ela.
  • Inicialização — @StateObject requer um valor inicial na criação, geralmente através de init com parâmetros.

O que é @StateObject no SwiftUI

@StateObject é um property wrapper introduzido no iOS 14 que permite a uma View criar e possuir uma instância de uma classe que está em conformidade com o protocolo ObservableObject. Ao contrário do @State, que trabalha com tipos de valor (structs), @StateObject é projetado para tipos de referência — classes que podem notificar o SwiftUI sobre alterações em suas propriedades.

Quando uma View usa @StateObject var viewModel: MyViewModel, o SwiftUI cria automaticamente uma instância de MyViewModel quando a View aparece pela primeira vez e a armazena em um armazenamento especial do framework. Em cada atualização da View (por exemplo, quando o estado pai muda), o SwiftUI não recria o objeto — ele usa a instância existente até que a View seja removida da hierarquia.

De acordo com a Apple WWDC Session 10137 (2024), @StateObject resolve o problema de perda de dados que existia no iOS 13 quando as Views eram reconstruídas, forçando os desenvolvedores a criar ObservableObject na View pai e passá-lo através do inicializador. Isso levava à duplicação de código e ao risco de recriar acidentalmente o objeto.

swift
import SwiftUI

class CounterViewModel: ObservableObject {
    @Published var count: Int = 0
    
    func increment() {
        count += 1
    }
}

struct CounterView: View {
    @StateObject var viewModel = CounterViewModel()
    
    var body: some View {
        VStack {
            Text("Count: \(viewModel.count)")
            Button("Increment", action: viewModel.increment)
        }
    }
}

Como o @StateObject funciona

O mecanismo do @StateObject é baseado na integração do SwiftUI com o framework Combine. Quando um ObservableObject marca suas propriedades com o atributo @Published, o SwiftUI se inscreve automaticamente nas alterações através do publisher incorporado ao protocolo ObservableObject. Quando uma propriedade publicada muda, o objeto envia um sinal através do publisher objectWillChange, o que desencadeia uma redesenho de todas as Views que observam este objeto.

O SwiftUI armazena a instância de ObservableObject em um armazenamento especial vinculado a uma instância específica de View. Este armazenamento é criado uma vez durante a primeira renderização e existe até que a View seja destruída. É por isso que o @StateObject garante a estabilidade da referência — o SwiftUI gerencia a memória automaticamente, sem depender do inicializador da View.

De acordo com objc.io — Thinking in SwiftUI (2025), a implementação interna do @StateObject usa um mecanismo semelhante ao @State, mas para tipos de referência: o SwiftUI cria um invólucro (boxing) ao redor do objeto e gerencia seu ciclo de vida através de seu próprio alocador, otimizado para reconstruções frequentes da hierarquia de Views.

Ciclo de vida do @StateObject

  • Criação — quando a View aparece pela primeira vez na tela, o SwiftUI chama o inicializador do objeto e armazena a referência.
  • Reconstrução — quando a View pai é atualizada, o objeto não é recriado; a instância existente é usada.
  • Destruição — quando a View sai da tela e é removida da hierarquia, o SwiftUI chama o deinit do objeto.

@StateObject vs @ObservedObject: diferenças principais

A principal diferença entre @StateObject e @ObservedObject está em quem possui o objeto. @StateObject cria e armazena o objeto — ele é o proprietário. @ObservedObject apenas observa o objeto que foi criado em outro lugar e passado através do inicializador ou de uma propriedade.

Característica@StateObject@ObservedObject
PropriedadeCria e possui o objetoApenas observa
InicializaçãoDentro da View via init/padrãoExterna, passada via parâmetro
Ciclo de vidaVinculado ao ciclo de vida da ViewNão controlado pela View
RecriaçãoNão é recriado na atualizaçãoPode ser substituído externamente
Versão iOSiOS 14+iOS 13+

A regra é simples: se a View cria o ObservableObject — use @StateObject. Se a View apenas recebe um objeto já criado do pai — use @ObservedObject. Violar esta regra leva à perda de dados (se usar @ObservedObject para propriedade) ou à criação excessiva de objetos (se usar @StateObject para observação).

Quando usar @StateObject

@StateObject deve ser usado nas Views que são a fonte de verdade para um conjunto específico de dados. Os cenários típicos incluem telas com seu próprio view model, telas raiz de pilhas de navegação e apresentações modais que gerenciam seu próprio estado.

  • Tela com view model — cada tela que gerencia seus próprios dados e lógica deve criar seu view model através de @StateObject.
  • View raiz — em uma hierarquia de NavigationStack ou TabView, o elemento raiz cria os dados, e os elementos filhos os recebem através de @ObservedObject.
  • Janelas modais — .sheet e .fullScreenCover geralmente exigem seu próprio @StateObject para gerenciar um formulário ou processo.
  • Lista editável — cada linha de lista que contém um formulário de edição deve ter seu próprio @StateObject.
swift
struct ProfileView: View {
    @StateObject var viewModel = ProfileViewModel()
    
    var body: some View {
        NavigationStack {
            Form {
                TextField("Name", text: $viewModel.name)
                TextField("Email", text: $viewModel.email)
                Button("Save") {
                    viewModel.saveProfile()
                }
            }
            .navigationTitle("Profile")
        }
    }
}

Inicializar @StateObject com parâmetros

Inicializar @StateObject com parâmetros requer uma sintaxe especial, já que o SwiftUI gerencia a criação do objeto por conta própria. Você não pode simplesmente passar parâmetros para o inicializador — é necessário usar um closure de escape ou um método de fábrica separado.

De acordo com Swift by Sundell (2024), a abordagem mais limpa é usar um método de fábrica ou closure que o SwiftUI chamará quando o objeto for criado pela primeira vez. Uma abordagem alternativa é inicializar o ObservableObject na View pai e passá-lo através de @StateObject usando o inicializador padrão.

swift
class UserViewModel: ObservableObject {
    @Published var user: User
    
    init(user: User) {
        self.user = user
    }
}

struct UserDetailView: View {
    @StateObject var viewModel: UserViewModel
    
    init(user: User) {
        _viewModel = StateObject(wrappedValue: UserViewModel(user: user))
    }
    
    var body: some View {
        Text(viewModel.user.name)
    }
}

É importante lembrar que o inicializador de View com @StateObject deve usar um underscore antes do nome da propriedade (_viewModel) para acessar o property wrapper em si, não seu valor. Este é um padrão Swift padrão para trabalhar com property wrappers em inicializadores.

Erros comuns com @StateObject

O erro mais comum é usar @ObservedObject em vez de @StateObject para uma View que deveria possuir o objeto. Neste caso, cada vez que o pai é reconstruído, o objeto será recriado, levando à perda de todos os dados acumulados. Este erro é especialmente insidioso em hierarquias complexas com NavigationStack ou TabView.

  • Perda de dados durante a navegação — se uma tela filha usa @ObservedObject para seu próprio view model, os dados serão redefinidos ao navegar de volta e reabrir.
  • Vazamento de memória — criar @StateObject em uma View pai que nunca é removida pode levar ao acúmulo de objetos se cada tela filha também criar @StateObject sem controle.
  • Duplicação de objetos — passar um único ObservableObject para múltiplos @StateObject em diferentes Views cria várias instâncias independentes que não se sincronizam entre si.

Para evitar esses problemas, siga uma regra simples: um @StateObject por fonte de verdade. Se os dados devem ser compartilhados entre várias telas — crie @StateObject uma vez na View raiz e passe através de @ObservedObject ou @EnvironmentObject para os elementos filhos.

swift
// ❌ Wrong: @ObservedObject for owning an object
struct BadView: View {
    @ObservedObject var vm = ViewModel() // will be recreated on each update!
}

// ✅ Correct: @StateObject for owning
struct GoodView: View {
    @StateObject var vm = ViewModel() // created once for View lifetime
}

Perguntas Frequentes

Qual é a diferença entre @StateObject e @State?

@State trabalha com tipos de valor (structs, strings, números) e armazena o valor diretamente no armazenamento do SwiftUI. @StateObject trabalha com tipos de referência — classes que estão em conformidade com ObservableObject. @State é adequado para estados locais simples, @StateObject para objetos complexos com lógica e propriedades publicadas.

Posso usar @StateObject no iOS 13?

Não, @StateObject está disponível apenas a partir do iOS 14. Para iOS 13, use @ObservedObject e crie o ObservableObject na View pai através de @State com gerenciamento manual de ciclo de vida. Uma alternativa é usar @State com um struct em vez de uma classe para dados que não exigem semântica de referência.

O que acontece se eu usar @StateObject em uma View filha onde o objeto é passado do pai?

A View filha criará sua própria cópia do ObservableObject, completamente independente da do pai. Alterações em uma não afetarão a outra. Isso é quase sempre um erro: use @ObservedObject para receber um objeto do pai e @StateObject apenas para criar um novo objeto dentro da View.

Quando um objeto criado via @StateObject é destruído?

O objeto é destruído quando a View que o criou é completamente removida da hierarquia do SwiftUI. Para uma tela no NavigationStack, isso ocorre ao fazer pop da pilha de navegação. Para uma janela modal — quando é fechada. Para TabView — ao alternar a aba, se a View não estiver em cache.

Como passar parâmetros para @StateObject durante a inicialização?

Use um init personalizado com acesso ao property wrapper através de underscore: _viewModel = StateObject(wrappedValue: MyViewModel(param: value)). Este padrão permite passar qualquer parâmetro para o ObservableObject, mantendo a garantia de criação única do objeto durante a vida da View.

Resumo

  • @StateObject — um property wrapper para criar e possuir um ObservableObject dentro de uma View, disponível desde iOS 14.
  • Garantia de criação única — o objeto é inicializado uma vez e não é recriado ao reconstruir a View.
  • Fonte de verdade — @StateObject é a fonte de verdade, enquanto @ObservedObject é apenas um observador.
  • Ciclo de vida — o objeto vive enquanto a View existe na hierarquia do SwiftUI e é destruído ao sair dela.
  • Inicialização com parâmetros — requer acesso ao property wrapper via _viewModel e StateObject(wrappedValue:).
  • Erro de propriedade — usar @ObservedObject para criar um objeto leva à perda de dados na reconstrução.
  • Um objeto — um @StateObject — para dados compartilhados, crie @StateObject na View raiz e passe para as filhas via @ObservedObject.

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.

Discutir o projeto

Leia também