@State é um Property Wrapper em SwiftUI para gerenciar estado local dentro de uma única view. O SwiftUI redesenha automaticamente a view sempre que uma propriedade @State muda, tornando a interface reativa sem chamadas manuais de atualização. De acordo com a Apple Developer Documentation (2025), @State é recomendado para tipos simples e estruturas pertencentes a uma única view. @State é a maneira mais simples de adicionar interatividade a uma interface SwiftUI.
Principais pontos
@State é um Property Wrapper integrado ao SwiftUI que permite que uma view armazene e monitore seu próprio estado. Quando um valor @State muda, o SwiftUI redesenha automaticamente a view reinvocando a propriedade body. Esta é a base da programação reativa no SwiftUI: o desenvolvedor declara o estado e o framework cuida da sincronização da interface.
@State cria uma área de armazenamento no heap gerenciada pelo SwiftUI. Esta área é persistente — ela sobrevive a inicializações repetidas da estrutura da view, que ocorrem a cada renderização. O SwiftUI usa o identificador da view (gerado a partir de sua posição na hierarquia) para vincular a propriedade @State a uma view específica. Graças a isso, o estado não é redefinido quando a view pai é atualizada.
Uma limitação importante: @State é destinado apenas a tipos de valor (structs, enums, primitivos). Para tipos de referência (classes), use @StateObject ou @ObservedObject. Se você atribuir uma classe a uma propriedade @State, o SwiftUI não conseguirá detectar alterações dentro do objeto — apenas a substituição completa da referência.
O SwiftUI implementa @State por meio de um mecanismo interno de Storage. Cada propriedade @State recebe uma célula de memória dedicada armazenada em um contêiner de armazenamento especial da view. Quando ocorre uma escrita em wrappedValue, o SwiftUI notifica seu grafo de dependências via didSet sobre a necessidade de redesenhar.
struct ContentView: View {
@State private var name: String = "User"
@State private var isLoggedIn: Bool = false
var body: some View {
VStack {
Text("Olá, \(name)")
Button(isLoggedIn ? "Sair" : "Entrar") {
isLoggedIn.toggle()
}
}
}
}
No exemplo, há duas propriedades @State: name (String) e isLoggedIn (Bool). Quando isLoggedIn.toggle() é chamado, o SwiftUI marca ContentView como precisando de atualização e reinvoca body no próximo ciclo de renderização. O ponto-chave: propriedades @State são sempre declaradas com o modificador private — isso sinaliza que o estado pertence exclusivamente à view atual e não deve ser alterado externamente diretamente.
Para observar mudanças, o SwiftUI usa CurrentValueSubject do Combine. Cada propriedade @State cria um publisher oculto que notifica o sistema a cada alteração. Isso permite que o SwiftUI redesenhe apenas o conjunto mínimo necessário de views, evitando atualizações completas da hierarquia.
@State é ideal para estados locais simples: campos de texto em pesquisa, flags booleanas para janelas modais, alternâncias de configuração, contadores, itens de lista selecionados. Se um valor é usado apenas em uma view e seus componentes filhos (via @Binding), @State é a escolha certa. Para estados que devem sobreviver ao fechamento da view (por exemplo, dados de formulário), @State também funciona enquanto a view permanecer na hierarquia.
Não use @State para estados globais da aplicação, cache de dados de rede ou objetos usados em várias telas. @StateObject e @EnvironmentObject são projetados para esses fins. Além disso, @State não é adequado para armazenar grandes quantidades de dados — cada alteração redesenhará a view inteira.
@Binding é uma ponte entre @State em uma view pai e uma view filha que precisa modificar esse estado. O pai declara @State, e o componente filho recebe um Binding por meio da projeção $. Alterar o Binding na view filha atualiza automaticamente o @State no pai — e vice-versa. Isso garante um fluxo de dados unidirecional com capacidade de feedback.
struct ParentView: View {
@State private var text: String = ""
var body: some View {
ChildView(text: $text)
}
}
struct ChildView: View {
@Binding var text: String
var body: some View {
TextField("Enter text", text: $text)
}
}
Na listagem, ParentView possui o @State text, e ChildView recebe $text como Binding. O TextField dentro de ChildView se vincula a este Binding via text: $text. Quando o usuário digita no TextField, o valor muda em ChildView através do Binding, o que causa uma atualização de @State em ParentView. Ambas as views são redesenhadas com o novo valor.
O erro mais comum é atribuir uma classe a uma propriedade @State. Se você escrever @State var model = MyClass(), o SwiftUI não conseguirá rastrear alterações nas propriedades dentro da classe — apenas a substituição do objeto. Para classes, sempre use @StateObject. O segundo problema comum é declarar @State sem o modificador private, o que viola o princípio de encapsulamento do estado.
Passar @State diretamente para uma view filha sem $ é outro erro típico. Se você passar TextField(text: text) em vez de TextField(text: $text), o componente filho receberá apenas uma string, não um Binding. As alterações de texto no TextField não serão sincronizadas com o @State do pai. Sempre use a projeção $ para passar Binding.
O terceiro erro são múltiplas propriedades @State para dados relacionados. Se vários valores formam logicamente um todo único (por exemplo, campos de formulário), combine-os em uma única estrutura com um único @State. Isso simplifica a passagem de estado para views filhas e reduz o número de gatilhos de atualização individuais.
@State é usado na maioria dos projetos SwiftUI para interatividade básica. Considere um exemplo de formulário de login onde @State gerencia campos de texto e estado de carregamento. Esse padrão aparece em todos os aplicativos — desde notas simples até soluções empresariais complexas.
struct LoginView: View {
@State private var email: String = ""
@State private var password: String = ""
@State private var isLoading: Bool = false
@State private var errorMessage: String?
var body: some View {
Form {
TextField("Email", text: $email)
SecureField("Password", text: $password)
Button("Entrar") {
login()
}.disabled(isLoading)
}
}
private func login() {
isLoading = true
// Realizar requisição de rede
}
}
No exemplo, há quatro propriedades @State: email e password para os campos do formulário, isLoading para indicação de carregamento e errorMessage para exibir erros. Cada propriedade gerencia independentemente sua parte da interface. Quando isLoading muda, o botão é automaticamente desabilitado via disabled(isLoading) — sem atualização manual da UI.
Perguntas frequentes
@State é projetado para o estado local de uma view específica. O modificador private garante que outros componentes não possam alterá-lo diretamente, quebrando o encapsulamento. Para acesso externo, use a projeção $.
Sim, @State suporta arrays e dicionários, pois são tipos de valor. No entanto, quando um elemento de um array muda, o SwiftUI redesenha a view inteira. Para listas grandes, @StateObject com @Published é mais eficiente.
@State funciona corretamente com tipos Optional. Quando nil é atribuído, o SwiftUI detecta a mudança e redesenha a view. Isso é conveniente para estados como errorMessage: String?, onde nil significa nenhum erro.
@State preserva o valor enquanto a view permanecer na hierarquia. Se a view for removida da hierarquia e adicionada novamente, @State é reinicializado com o valor padrão. Para persistência, use @AppStorage.
Sim, envolva a alteração em withAnimation: withAnimation(.easeInOut) { isExpanded.toggle() }. O SwiftUI anima a transição entre o estado antigo e o novo da interface com o tipo de animação especificado.
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