A propriedade body é o elemento central do protocolo View no SwiftUI, determinando qual conteúdo é exibido na tela. De acordo com Apple Developer Documentation, 2024, body é o único requisito obrigatório do protocolo View e retorna algum tipo que está em conformidade com este mesmo protocolo. O SwiftUI chama body a cada mudança de estado para construir e comparar uma nova árvore de elementos.
Pontos Principais
body é uma propriedade computada que é o único requisito obrigatório do protocolo View. Toda estrutura em conformidade com View deve implementar body. A propriedade retorna o conteúdo que o SwiftUI exibe na tela — pode ser texto, uma imagem, um botão, um contêiner com elementos aninhados ou qualquer outro tipo em conformidade com o protocolo View.
A assinatura do body é sempre fixa: var body: some View { get }. O tipo de retorno é some View (um tipo opaco), não um tipo concreto. Isso significa que diferentes Views podem retornar diferentes tipos concretos em body, mas o compilador Swift fixa o tipo concreto para cada implementação em tempo de compilação.
De acordo com a WWDC 2022, body é o ponto de entrada para a descrição declarativa da interface. Diferente do UIKit, onde você cria e configura UIView imperativamente, no SwiftUI você descreve declarativamente o que deve ser exibido, e o próprio SwiftUI calcula como implementá-lo.
body deve se comportar como uma função pura — com as mesmas entradas (propriedades da estrutura e estado) deve retornar a mesma árvore View. Se body depender de estado mutável externo (variáveis globais, UserDefaults sem o wrapper @AppStorage), o comportamento se torna imprevisível e o SwiftUI pode redesenhar a tela incorretamente.
A propriedade computada body não armazena um valor — ela é calculada cada vez que é acessada. Quando o SwiftUI determina que o estado mudou, ele recria a estrutura View e lê o novo valor de body para obter a árvore de elementos atual para exibição.
struct CounterView: View {
@State private var count = 0
var body: some View {
VStack {
Text("Contador: \(count)")
.font(.largeTitle)
Button("Incrementar") {
count += 1
}
.padding()
.background(.blue)
.foregroundColor(.white)
.cornerRadius(8)
}
}
}
Neste exemplo, body retorna um VStack contendo um Text e um botão com modificadores. Quando o botão é pressionado, a propriedade @State count é incrementada, o SwiftUI recria a estrutura CounterView e chama body novamente para obter a árvore atualizada com o novo valor do Text.
Os modificadores (.font, .padding, .background, .foregroundColor, .cornerRadius) não modificam a View original, mas a envolvem em ModifiedContent — um novo tipo que adiciona a modificação. Cada modificador cria outro nível de aninhamento, o que é importante considerar para o desempenho.
some View no tipo de retorno de body não é apenas uma convenção, mas um requisito do compilador. O Swift exige que todos os caminhos de retorno em body tenham o mesmo tipo concreto. Sem @ViewBuilder você não pode retornar Text em um ramo e Button em outro — o compilador produzirá um erro.
struct ConditionalView: View {
var isReady: Bool
@ViewBuilder
var body: some View {
if isReady {
Text("Pronto")
.foregroundColor(.green)
} else {
ProgressView()
}
}
}
@ViewBuilder em body permite usar lógica condicional (if/else, switch) sem erros de compilação. O ViewBuilder envolve automaticamente diferentes ramos em ConditionalContent — um tipo especial que oculta as diferenças de tipos concretos. Esta é uma capacidade fundamental para construir interfaces dinâmicas.
Sem @ViewBuilder, o compilador tenta inferir um único tipo para todos os caminhos de retorno. Se os tipos diferirem — ocorre um erro. É por isso que o SwiftUI aplica implicitamente @ViewBuilder a body nas declarações View, embora no código do usuário você precise adicionar a anotação explicitamente para métodos e propriedades personalizados que retornam várias Views.
Usar some View em vez de um tipo concreto não reduz o desempenho — o compilador conhece o tipo exato em tempo de compilação e gera código direto sem despacho dinâmico. AnyView, ao contrário, usa apagamento de tipo (type erasure) com a sobrecarga de envolver em um contêiner existencial.
body é chamado pelo SwiftUI em três cenários principais: quando a View é exibida pela primeira vez, quando @State/@Binding/@ObservedObject/@StateObject muda, e quando a View pai passa novos valores através do inicializador. O SwiftUI também pode chamar body quando os valores de ambiente (@Environment) mudam.
A frequência das chamadas a body não deve preocupá-lo — o SwiftUI otimiza o redesenho através do mecanismo de identidade. Cada View na hierarquia tem um identificador único. Se a identidade e os dados de entrada não mudaram — body não é chamado mesmo que a View pai seja redesenhada. Isso é alcançado através da comparação Equatable e da estabilidade estrutural.
struct ParentView: View {
var body: some View {
ChildView(name: "Alice") // Identidade estável
}
}
struct ChildView: View {
let name: String
var body: some View {
Text("Olá, \(name)!")
}
}
Neste exemplo, se ParentView for redesenhada mas passar o mesmo valor de name — ChildView.body não é chamado. O SwiftUI compara os dados de entrada da estrutura e, se não mudaram, ignora o redesenho do componente filho. Este é o mecanismo de diferenciação de views.
Existem várias armadilhas que levam a chamadas inesperadas de body: usar classes sem ObservableObject, passar clousures criadas dentro de body (cada criação de clousure gera uma nova identidade), e o uso incorreto de EquatableView. Se body é chamado com muita frequência — verifique a estabilidade de identidade de todos os componentes filhos.
Primeira regra: body deve ser mínimo. Mova a lógica complexa para propriedades computadas ou métodos separados que retornam View. Isso melhora a legibilidade e permite que o SwiftUI determine com mais precisão quais partes da hierarquia mudaram. Divida bodies grandes em subcomponentes com limites de responsabilidade claros.
Segunda regra: não use body para realizar trabalho. Carregamento de dados, operações de rede, gravações em banco de dados — tudo isso deve acontecer fora de body, em tarefas (tasks), modificadores onChange ou através de ObservableObject. body é destinado exclusivamente à declaração da interface.
Terceira regra: use a propriedade EquatableView ou um protocolo Equatable personalizado para Views se a comparação estrutural padrão for insuficiente. Isso permite indicar explicitamente ao SwiftUI quando uma View filha precisa ser redesenhada e evitar chamadas desnecessárias a body.
Quarta regra: se body contiver cálculos complexos (formatação, filtragem, ordenação) — use @State para armazenar em cache o resultado ou mova os cálculos para um método separado chamado a partir de onChange. Cálculos repetidos em body a cada atualização de estado são uma causa comum de lentidão de animações.
Quinta regra: para listas (List, ForEach) garanta identificadores estáveis através do parâmetro id. Sem identidade estável, ForEach recria todos os elementos em qualquer alteração, chamando body para cada um deles, mesmo que apenas um elemento tenha mudado.
Perguntas Frequentes
body é a propriedade computada do protocolo View que retorna o conteúdo para exibição. É o único requisito obrigatório do protocolo. O tipo de retorno é some View, o que permite ao SwiftUI otimizar a hierarquia em tempo de compilação.
Sim, o SwiftUI chama body a cada mudança de estado (@State, @Binding, @ObservedObject) ou de dados de entrada. Este é um comportamento normal de um framework declarativo. O SwiftUI otimiza a frequência de chamadas através do mecanismo de identidade e da comparação Equatable.
some View é um tipo opaco que oculta a implementação concreta. O compilador fixa o tipo em tempo de compilação, garantindo o desempenho de chamada direta. Isso oferece flexibilidade: você pode alterar o tipo de retorno sem alterar a assinatura.
Não, body não pode ser opcional — o tipo de retorno some View não permite nil. Se precisar ocultar um elemento condicionalmente, use lógica condicional dentro de @ViewBuilder ou retorne EmptyView, que não ocupa espaço na hierarquia.
Cada modificador cria uma nova camada de ModifiedContent, aumentando a profundidade da hierarquia. Para a maioria das telas (até 50 modificadores) o impacto é insignificante. Uma quantidade excessiva de modificadores (centenas) pode retardar o diffing. Agrupe modificadores relacionados em extensões personalizadas.
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