some View es una construcción sintáctica clave de Swift sin la cual SwiftUI no puede funcionar. Según Apple Swift Book, 2024, some View es un tipo opaco (opaque type) que oculta el tipo de retorno específico manteniendo al mismo tiempo una tipificación estricta en tiempo de compilación. Esta construcción permite que el protocolo View tenga una única signatura body sin revelar detalles de implementación.
Puntos clave
some View es una sintaxis de tipo opaco introducida en Swift 5.1. Se utiliza como tipo de retorno de la propiedad body del protocolo View. La notación some View significa: “la función o propiedad devuelve algún tipo concreto que cumple con el protocolo View, pero el código llamante no sabe ni debe saber cuál”.
El concepto de tipo opaco es la cara inversa de la programación genérica (generics). Si los generics permiten que el código llamante determine el tipo, el tipo opaco permite que la implementación determine el tipo, ocultándolo del llamante. Esto le da al desarrollador la libertad de cambiar la implementación interna sin modificar el contrato.
Según Swift Evolution SE-0244, los tipos opacos se añadieron para soportar SwiftUI y el patrón de protocolos con tipos asociados (PAT), que no se pueden usar como tipo de retorno sin esta construcción.
Sin some View, la signatura de body sería imposible: el protocolo View tiene un tipo asociado Body que cumple con View. Si body devolviera simplemente View (como protocolo), Swift no podría trabajar con protocolos con requisitos Self en la posición de retorno. some View resuelve este problema proporcionando un tipo concreto pero oculto.
El tipo opaco es un tipo especial que se comporta como concreto para el compilador pero como abstracto para el desarrollador. Cuando el compilador ve some View, analiza la implementación y determina el tipo de retorno exacto. Este tipo se fija y se utiliza para la generación de código sin despacho dinámico.
struct SimpleView: View {
var body: some View {
Text("Hello")
}
}
// Compiler sees: body -> Text, not some View
Principio de funcionamiento: El compilador de Swift infiere el tipo concreto de la implementación. En el ejemplo anterior, el cuerpo contiene solo Text, por lo que el compilador sabe que body devuelve exactamente Text, aunque la signatura esté escrita como some View. Esto proporciona dos optimizaciones: llamada directa sin tabla de métodos virtuales y posibilidad de inlining.
Si la implementación de body cambia (por ejemplo, en lugar de Text se devuelve un VStack de Text y Button), el compilador redefine el tipo concreto. Pero para el código llamante (SwiftUI), la signatura sigue siendo la misma — some View. Esta es la cara inversa de los generics: el código llamante no depende de los cambios en la implementación.
Una de las reglas clave de los tipos opacos: una función o propiedad que devuelve some View debe devolver siempre el mismo tipo concreto. No se puede devolver Text en una rama if e Image en otra. Esta limitación la verifica el compilador y sirve como garantía para el código llamante.
struct BadView: View {
var flag: Bool
var body: some View {
if flag {
Text("True") // Error: Text vs VStack
} else {
VStack {
Text("False")
Image(systemName: "xmark")
}
}
}
}
Para resolver este problema se utiliza @ViewBuilder, que envuelve diferentes ramas en un contenedor condicional ConditionalContent. La anotación @ViewBuilder sobre body es una práctica estándar en SwiftUI, aunque puede ser implícita si body contiene solo una expresión.
AnyView es un tipo que borra la implementación concreta de View (type erasure). Envuelve cualquier View en un único envoltorio, permitiendo almacenar Views de diferentes tipos en un mismo contenedor. A diferencia de some View, AnyView funciona en tiempo de ejecución y añade sobrecarga de envoltura y desempaquetado.
| Criterio | some View | AnyView |
|---|---|---|
| Momento de resolución | compilación | ejecución |
| Rendimiento | llamada directa, sin sobrecarga | envoltura en existential container |
| Flexibilidad de tipos | un solo tipo concreto | cualquier tipo View |
| Cambio dinámico | no soportado | soportado en tiempo de ejecución |
| Prioridad de uso | siempre que sea posible | solo cuando some View es imposible |
| Soporte de protocolos PAT | sí | sí |
Cuándo usar AnyView: solo en situaciones donde some View es imposible debido a la necesidad de cambio dinámico de tipo en tiempo de ejecución. Por ejemplo, al devolver una View desde un diccionario o en una estructura recursiva donde el tipo concreto debe cambiar en cada nivel. AnyView debe minimizarse, ya que cada envoltura desactiva las optimizaciones de SwiftUI.
@ViewBuilder es un result builder diseñado específicamente para trabajar con some View. Permite usar lógica condicional (if/else, switch) y múltiples expresiones en el cuerpo manteniendo un único tipo de retorno. ViewBuilder envuelve automáticamente múltiples expresiones en TupleView y las ramas condicionales en 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...")
}
}
}
Cómo funciona: @ViewBuilder analiza el bloque de código y genera la llamada adecuada buildBlock, buildOptional o buildEither. Para la lógica condicional se crea ConditionalContent — un tipo común que oculta los tipos concretos dentro de las ramas pero que en sí mismo es un tipo único para el compilador. Esto resuelve el problema de diferentes tipos concretos.
Sin @ViewBuilder, una propiedad body que contenga múltiples expresiones o lógica condicional provocaría un error de compilación. Es por eso que SwiftUI aplica @ViewBuilder a body implícitamente, y para propiedades y funciones personalizadas debe añadirse explícitamente.
@ViewBuilder puede anidarse: un ViewBuilder dentro de otro. Esto permite crear jerarquías complejas con condiciones en diferentes niveles. Sin embargo, el anidamiento profundo dificulta la legibilidad, por lo que se recomienda extraer las condiciones anidadas en componentes View separados.
Ejemplo 1: devolver una View personalizada desde una propiedad computada. Una propiedad puede devolver some View, ocultando la composición interna. Esto permite reorganizar el código sin cambiar la interfaz 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)
}
}
Ejemplo 2: pasar una View como clausura mediante @ViewBuilder. Este patrón se usa en los contenedores estándar de SwiftUI (VStack, HStack, List) y puede implementarse en componentes personalizados.
struct CustomContainer<Content: View>: View {
@ViewBuilder let content: () -> Content
var body: some View {
VStack(alignment: .leading) {
content()
}
.padding(20)
}
}
Ejemplo 3: una función de fábrica que devuelve some View. Permite crear Views según parámetros sin revelar la implementación. Esto es especialmente útil para bibliotecas y componentes reutilizables.
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()
}
}
Preguntas frecuentes
some View es un tipo opaco, lo que significa que se devuelve algún tipo concreto que cumple con el protocolo View. El tipo concreto lo fija el compilador pero se oculta del código llamante. Esto proporciona una tipificación estricta sin revelar detalles de implementación.
some View se resuelve en tiempo de compilación con sobrecarga cero. AnyView usa borrado de tipo (type erasure) en tiempo de ejecución con costes adicionales de envoltura en un existential container. Use some View siempre que sea posible, AnyView solo para cambio dinámico de tipo.
Un tipo opaco requiere un único tipo concreto para todas las rutas de retorno. if/else con diferentes tipos viola este requisito. @ViewBuilder resuelve el problema envolviendo las ramas en ConditionalContent — un tipo único que oculta las diferencias de las implementaciones concretas.
some View no reduce el rendimiento — el compilador conoce el tipo exacto y genera código directo. Por el contrario, any View (como protocolo) requeriría despacho dinámico. some View es un mecanismo de optimización integrado en el diseño de SwiftUI.
Sí, some es una construcción general de Swift 5.1 no vinculada a SwiftUI. Se puede usar con cualquier protocolo: some Equatable, some Codable, some Collection. Es útil para ocultar tipos anidados complejos como [String: [Int]].
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también