some View é uma construção sintática fundamental do Swift sem a qual o SwiftUI não pode funcionar. De acordo com Apple Swift Book, 2024, some View é um tipo opaco (opaque type) que oculta o tipo de retorno específico mantendo a tipagem estrita em tempo de compilação. Essa construção permite que o protocolo View tenha uma única assinatura body sem revelar detalhes de implementação.
Principais pontos
some View é uma sintaxe de tipo opaco introduzida no Swift 5.1. É usada como tipo de retorno da propriedade body do protocolo View. A notação some View significa: “a função ou propriedade retorna algum tipo concreto que está em conformidade com o protocolo View, mas o código chamador não sabe e não deve saber qual é”.
O conceito de tipo opaco é o lado inverso da programação genérica (generics). Se os generics permitem que o código chamador determine o tipo, o tipo opaco permite que a implementação determine o tipo, ocultando-o do chamador. Isso dá ao desenvolvedor a liberdade de alterar a implementação interna sem modificar o contrato.
De acordo com Swift Evolution SE-0244, os tipos opacos foram adicionados para suportar SwiftUI e o padrão de protocolos com tipos associados (PAT), que não podem ser usados como tipo de retorno sem esta construção.
Sem some View, a assinatura body seria impossível: o protocolo View tem um tipo associado Body que está em conformidade com View. Se body retornasse simplesmente View (como protocolo), o Swift não conseguiria trabalhar com protocolos com requisitos Self na posição de retorno. some View resolve este problema fornecendo um tipo concreto mas oculto.
Tipo opaco é um tipo especial que se comporta como concreto para o compilador mas como abstrato para o desenvolvedor. Quando o compilador vê some View, ele analisa a implementação e determina o tipo de retorno exato. Este tipo é fixado e usado para geração de código sem despacho dinâmico.
struct SimpleView: View {
var body: some View {
Text("Olá")
}
}
// Compiler sees: body -> Text, not some View
Princípio de funcionamento: O compilador Swift infere o tipo concreto da implementação. No exemplo acima, o corpo contém apenas Text, então o compilador sabe que body retorna exatamente Text, mesmo que a assinatura esteja escrita como some View. Isso proporciona duas otimizações: chamada direta sem tabela de métodos virtuais e possibilidade de inlining.
Se a implementação de body mudar (por exemplo, em vez de Text, um VStack de Text e Button for retornado), o compilador redefine o tipo concreto. Mas para o código chamador (SwiftUI), a assinatura permanece a mesma — some View. Este é o lado inverso dos generics: o código chamador não depende de alterações na implementação.
Uma das regras principais dos tipos opacos: uma função ou propriedade que retorna some View deve sempre retornar o mesmo tipo concreto. Não é possível retornar Text em um ramo if e Image em outro. Esta limitação é verificada pelo compilador e serve como garantia para o código chamador.
struct BadView: View {
var flag: Bool
var body: some View {
if flag {
Text("Verdadeiro") // Erro: Text vs VStack
} else {
VStack {
Text("Falso")
Image(systemName: "xmark")
}
}
}
}
Para resolver este problema, utiliza-se @ViewBuilder, que envolve diferentes ramos em um contêiner condicional ConditionalContent. A anotação @ViewBuilder sobre body é uma prática padrão no SwiftUI, embora possa ser implícita se body contiver apenas uma expressão.
AnyView é um tipo que apaga a implementação concreta de View (type erasure). Ele envolve qualquer View em um único invólucro, permitindo armazenar Views de diferentes tipos no mesmo contêiner. Ao contrário de some View, AnyView funciona em tempo de execução e adiciona overhead de encapsulamento e desencapsulamento.
| Critério | some View | AnyView |
|---|---|---|
| Tempo de resolução | compilação | execução |
| Desempenho | chamada direta, sem overhead | encapsulamento em existential container |
| Flexibilidade de tipos | um único tipo concreto | qualquer tipo View |
| Alteração dinâmica | não suportado | suportado em tempo de execução |
| Prioridade de uso | sempre que possível | apenas quando some View é impossível |
| Suporte a protocolos PAT | sim | sim |
Quando usar AnyView: apenas em situações onde some View é impossível devido à necessidade de alteração dinâmica de tipo em tempo de execução. Por exemplo, ao retornar uma View de um dicionário ou em uma estrutura recursiva onde o tipo concreto deve mudar em cada nível. AnyView deve ser minimizado, pois cada encapsulamento desativa as otimizações do SwiftUI.
Equívoco comum: AnyView não resolve o problema de tipos diferentes em body — @ViewBuilder resolve isso. AnyView apaga o tipo mas não ajuda o compilador a inferir um tipo único. Use @ViewBuilder para lógica condicional e AnyView apenas para despacho dinâmico.
@ViewBuilder é um result builder projetado especificamente para trabalhar com some View. Ele permite usar lógica condicional (if/else, switch) e múltiplas expressões no corpo mantendo um único tipo de retorno. ViewBuilder envolve automaticamente múltiplas expressões em TupleView e ramos condicionais em ConditionalContent.
struct ProfileView: View {
let user: User?
@ViewBuilder
var body: some View {
if let user {
UserCard(user: user)
Text("Online")
.font(.caption)
} else {
ProgressView("Loading...")
}
}
}
Como funciona: @ViewBuilder analisa o bloco de código e gera a chamada apropriada buildBlock, buildOptional ou buildEither. Para lógica condicional, é criado ConditionalContent — um tipo comum que oculta os tipos concretos dentro dos ramos mas é em si um único tipo para o compilador. Isto resolve o problema de diferentes tipos concretos.
Sem @ViewBuilder, uma propriedade body contendo múltiplas expressões ou lógica condicional causaria um erro de compilação. É por isso que o SwiftUI aplica @ViewBuilder a body implicitamente, e para propriedades e funções personalizadas deve ser adicionado explicitamente.
@ViewBuilder pode ser aninhado: um ViewBuilder dentro de outro. Isso permite criar hierarquias complexas com condições em diferentes níveis. No entanto, o aninhamento profundo dificulta a legibilidade, por isso é recomendável extrair condições aninhadas em componentes View separados.
Exemplo 1: retornar uma View personalizada de uma propriedade computada. Uma propriedade pode retornar some View, ocultando a composição interna. Isso permite reorganizar o código sem alterar a interface pública.
struct ArticleView: View {
var body: some View {
CardView {
HeaderView()
ContentView()
FooterView()
}
}
}
struct CardView<Content: View>: View {
let content: Content
var body: some View {
content
.padding(16)
.background(.white)
.cornerRadius(12)
.shadow(radius: 4)
}
}
Exemplo 2: passar uma View como closure via @ViewBuilder. Este padrão é usado nos contêineres padrão do SwiftUI (VStack, HStack, List) e pode ser implementado em componentes personalizados.
struct CustomContainer<Content: View>: View {
@ViewBuilder let content: () -> Content
var body: some View {
VStack(alignment: .leading) {
content()
}
.padding(20)
}
}
Exemplo 3: uma função de fábrica que retorna some View. Permite criar Views dependendo de parâmetros sem revelar a implementação. Isto é especialmente útil para bibliotecas e componentes reutilizáveis.
func makeIcon(for status: Status) -> some View {
switch status {
case .success:
Image(systemName: "checkmark.circle.fill")
.foregroundColor(.green)
case .error:
Image(systemName: "xmark.circle.fill")
.foregroundColor(.red)
case .pending:
ProgressView()
}
}
Perguntas frequentes
some View é um tipo opaco, significando que algum tipo concreto em conformidade com o protocolo View é retornado. O tipo concreto é fixado pelo compilador mas oculto do código chamador. Isso fornece tipagem estrita sem revelar detalhes de implementação.
some View é resolvido em tempo de compilação com zero de overhead. AnyView usa type erasure em tempo de execução com custos adicionais de encapsulamento em um existential container. Use some View sempre que possível, AnyView apenas para alteração dinâmica de tipo.
Um tipo opaco requer um único tipo concreto para todos os caminhos de retorno. if/else com tipos diferentes viola este requisito. @ViewBuilder resolve o problema envolvendo os ramos em ConditionalContent — um tipo único que oculta as diferenças das implementações concretas.
some View não reduz o desempenho — o compilador conhece o tipo exato e gera código direto. Por outro lado, any View (como protocolo) exigiria despacho dinâmico. some View é um mecanismo de otimização integrado no design do SwiftUI.
Sim, some é uma construção geral do Swift 5.1 não vinculada ao SwiftUI. Pode ser usada com qualquer protocolo: some Equatable, some Codable, some Collection. É útil para ocultar tipos aninhados complexos como [String: [Int]].
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