Desarrolladores
¿«Cannot find 'Map' in scope» en SwiftUI? Arregla los imports de Map y WebView
Soluciona «Cannot find 'Map' in scope» en SwiftUI: por qué Map, PhotosPicker y WebView necesitan otro import y cómo usar WebView y WebPage en iPhone y iPhone Duo.
Por la redacción de AppleDuoPublicado 8 min de lectura
En esta página
- ¿Por qué SwiftUI dice «Cannot find 'Map' in scope»?
- ¿Qué es un cross-import overlay en Swift?
- ¿Qué vistas de SwiftUI necesitan un segundo import?
- ¿Cómo uso el WebView nativo de SwiftUI en iOS 26?
- ¿Cómo sigo la carga, la navegación y JavaScript con WebPage?
- ¿Cómo doy soporte a versiones de iOS anteriores a la 26?
- ¿Los mapas y las vistas web necesitan algo especial en iPhone Duo?
- Puntos clave
Añades un mapa a una vista de SwiftUI, el archivo ya tiene import SwiftUI y Xcode se detiene con «Cannot find 'Map' in scope». El tipo existe, está bien escrito y el deployment target es correcto. Lo mismo ocurre con PhotosPicker y con el WebView nativo que SwiftUI incorporó en iOS 26. La solución es un solo import, pero la razón que hay detrás explica toda una familia de errores.
Esta guía explica por qué aparece el error, qué es un cross-import overlay, qué vistas necesitan un segundo import y cómo usar el WebView de iOS 26 con WebPage. Se basa en la documentación y las sesiones de la WWDC de Apple, en las notas de diseño de los Swift Forums y en publicaciones del desarrollador de iOS @sarunw. WebView y WebPage son nuevos en iOS 26.0, y los detalles pueden cambiar entre versiones.
¿Por qué SwiftUI dice «Cannot find 'Map' in scope»?
Porque Map no forma parte de SwiftUI. Como dice @sarunw, Map vive en un cross-import overlay, así que necesitas tanto SwiftUI como MapKit. Este archivo no compila:
import SwiftUI
struct ContentView: View {
var body: some View {
Map() // error: cannot find 'Map' in scope
}
}
Añade una línea y compila:
import SwiftUI
import MapKit
struct ContentView: View {
var body: some View {
Map()
}
}
La documentación de Map de Apple la clasifica dentro de MapKit y la describe como una vista de SwiftUI. El nombre interno del símbolo la sitúa en un módulo llamado _MapKit_SwiftUI, que no es ni MapKit ni SwiftUI. Ese tercer módulo es el overlay.
Dos detalles hacen que el error cueste más de detectar. El mensaje del compilador no menciona que falte un import y, como señala @sarunw en su artículo sobre los cross-import overlays, el autocompletado de Xcode no puede sugerir un tipo de un módulo que no está cargado. Así que Map tampoco aparece en las sugerencias.
¿Qué es un cross-import overlay en Swift?
Un cross-import overlay es un módulo que el compilador importa automáticamente cuando un archivo de código importa dos módulos concretos. La discusión de diseño de los Swift Forums describe overlays elegidos a partir de «la combinación de imports de un archivo de código». El overlay reexporta el primer framework, llamado módulo declarante, y añade API que también necesita el segundo, llamado módulo acompañante.
¿Por qué no poner Map directamente en SwiftUI o en MapKit? Map es una View, así que necesita SwiftUI, y trabaja con tipos de MapKit, así que necesita MapKit. Ponerla en cualquiera de los dos frameworks obligaría a toda app que use uno a cargar también el otro. El overlay solo se carga cuando un archivo ha pedido ambos.
Puedes ver el mecanismo en el SDK. Según @sarunw, un framework con overlays incluye una carpeta .swiftcrossimport en su directorio Modules, con un pequeño archivo por cada módulo asociado:
SDK=$(xcrun --sdk iphonesimulator --show-sdk-path)
cd "$SDK/System/Library/Frameworks/MapKit.framework/Modules"
ls MapKit.swiftcrossimport
cat MapKit.swiftcrossimport/SwiftUI.swiftoverlay
El archivo SwiftUI.swiftoverlay es un breve archivo YAML que nombra el módulo overlay, _MapKit_SwiftUI. @sarunw cuenta 36 cross-import overlays en el SDK de iOS 26.
Hay una consecuencia que importa en el día a día: los imports son por archivo. Importar MapKit en el punto de entrada de tu app no hace que Map esté disponible en otro archivo que solo importa SwiftUI. Cada archivo que usa la vista necesita ambos imports.
¿Qué vistas de SwiftUI necesitan un segundo import?
La regla práctica de @sarunw: localiza los dos frameworks de los que depende el tipo e importa ambos. Estos son los más comunes, con la disponibilidad según la documentación de Apple:
| API de SwiftUI | Importa también | Disponible desde |
|---|---|---|
Map, Marker, Annotation | MapKit | iOS 14 (Map); iOS 17 para el contenido del mapa |
PhotosPicker | PhotosUI | iOS 16 |
WebView | WebKit | iOS 26 |
VideoPlayer | AVKit | iOS 14 |
SubscriptionStoreView | StoreKit | iOS 17 |
SpriteView | SpriteKit | iOS 14 |
SignInWithAppleButton | AuthenticationServices | iOS 14 |
La documentación de Apple registra cada uno de estos símbolos como perteneciente tanto a su framework como a SwiftUI. El artículo de @sarunw añade más parejas, como ProductView con StoreKit, .quickLookPreview(_:) con QuickLook, SceneView y RealityView con SceneKit y RealityKit, .translationPresentation con Translation y .modelContainer con SwiftData.
Así que, cuando veas «Cannot find 'X' in scope» para un tipo que parece de SwiftUI, comprueba si falta un segundo import antes de sospechar de una errata o de un problema de disponibilidad. La API de construcción de contenido de MapKit, con Marker y Annotation dentro de Map, llegó en iOS 17 con la sesión de Apple Meet MapKit for SwiftUI.
¿Cómo uso el WebView nativo de SwiftUI en iOS 26?
Antes de iOS 26, mostrar una página web en SwiftUI significaba envolver WKWebView en un UIViewRepresentable. Como dice @sarunw, SwiftUI por fin tiene un WebView nativo en iOS 26. La sesión de Apple What's new in SwiftUI lo presenta como una nueva vista de SwiftUI para mostrar contenido web en tu app, impulsada por WebKit igual que Safari.
WebView también es un tipo de cross-import overlay. La documentación de WebView de Apple lo incluye en WebKit y en SwiftUI, y sus ejemplos empiezan con ambos imports. Para una página de condiciones o un artículo de ayuda, el inicializador con URL es todo lo que necesitas:
import SwiftUI
import WebKit
struct HelpView: View {
var body: some View {
NavigationStack {
WebView(url: URL(string: "https://www.swift.org"))
.navigationTitle("Help")
.webViewBackForwardNavigationGestures(.disabled)
}
}
}
init(url:) recibe una URL opcional, y los enlaces dentro de la página funcionan como en un navegador. Apple señala que un WebView se desplaza como un ScrollView y acepta scrollBounceBehavior(_:axes:). WebKit añade modificadores como webViewBackForwardNavigationGestures(_:), webViewLinkPreviews(_:), webViewTextSelection(_:) y webViewContentBackground(_:). El modificador existente findNavigator(isPresented:) añade la búsqueda en la página, según la sesión de Apple Meet WebKit for SwiftUI.
¿Cómo sigo la carga, la navegación y JavaScript con WebPage?
El inicializador con URL no te dice nada sobre la página. Cuando necesitas el título, el progreso o JavaScript, el consejo de @sarunw es combinar WebView con WebPage. La documentación de WebPage de Apple lo describe como una clase Observable que controla y gestiona contenido web interactivo. Guárdalo en @State y pásalo a WebView(_:):
import SwiftUI
import WebKit
struct BrowserView: View {
@State private var page = WebPage()
var body: some View {
NavigationStack {
WebView(page)
.navigationTitle(page.title)
.safeAreaInset(edge: .top) {
if page.isLoading {
ProgressView(value: page.estimatedProgress)
}
}
.toolbar {
Button("Reload", systemImage: "arrow.clockwise") {
page.reload(fromOrigin: false)
}
}
}
.onAppear {
page.load(URLRequest(url: URL(string: "https://www.webkit.org")!))
}
}
}
Como WebPage es observable, el título y la barra de progreso se actualizan solos, sin delegado ni coordinador. La documentación de Apple añade que un WebPage solo puede vincularse a un WebView a la vez. Estos son los miembros que usarás primero:
| Miembro de WebPage | Qué te da |
|---|---|
title, url | El título de la página y la URL actual |
isLoading, estimatedProgress | Estado de carga y progreso de 0 a 1 |
themeColor | El color de la metaetiqueta theme-color de la página |
backForwardList | El historial, desde el que puedes cargar un elemento |
load(_:), load(html:baseURL:) | Navegación, que devuelve una secuencia asíncrona de eventos |
callJavaScript(_:arguments:in:contentWorld:) | Ejecutar JavaScript y obtener un resultado |
Cada llamada a load devuelve una secuencia asíncrona de eventos de navegación. La sesión de Apple dice que una navegación empieza con startedProvisionalNavigation y después termina o falla. Recorre la secuencia con for try await cuando necesites esperar a que termine de cargar una página, o lee currentNavigationEvent desde una vista.
Para JavaScript, callJavaScript es async throws y devuelve un Any opcional. Las claves del diccionario arguments se convierten en variables locales dentro del script:
let heading = try await page.callJavaScript(
"return document.querySelector(selector)?.textContent",
arguments: ["selector": "h1"]
) as? String
Para permitir o bloquear navegaciones, haz que un tipo cumpla WebPage.NavigationDeciding y pásalo a WebPage(configuration:navigationDecider:). La sesión de Apple también trata los esquemas de URL personalizados mediante el protocolo URLSchemeHandler.
¿Cómo doy soporte a versiones de iOS anteriores a la 26?
WebView y WebPage requieren iOS 26 o posterior. Si tu deployment target es inferior, mantén un envoltorio de WKWebView y elige en tiempo de ejecución, como sugiere @sarunw:
struct ArticleView: View {
let url: URL
var body: some View {
if #available(iOS 26.0, *) {
WebView(url: url)
} else {
LegacyWebView(url: url)
}
}
}
struct LegacyWebView: UIViewRepresentable {
let url: URL
func makeUIView(context: Context) -> WKWebView {
WKWebView()
}
func updateUIView(_ webView: WKWebView, context: Context) {
webView.load(URLRequest(url: url))
}
}
El archivo sigue necesitando import SwiftUI e import WebKit. La ruta heredada recarga cada vez que SwiftUI actualiza la vista, así que en una app real compara la URL actual antes de llamar a load. Una desarrolladora, Sarah Reichelt, descubrió que el ejemplo de seguimiento de navegación de la sesión dejó de compilar en betas posteriores de iOS 26, así que comprueba los ejemplos con tu versión de Xcode.
¿Los mapas y las vistas web necesitan algo especial en iPhone Duo?
Los imports funcionan igual en todos los iPhone, pero iPhone Duo cambia el espacio en el que viven estas vistas.
- Más espacio al abrirlo. La pantalla interior informa ancho regular y alto regular en ambas orientaciones, como explica nuestra guía de size classes en iPhone Duo. Un mapa o una vista web pueden situarse junto a una lista en un
NavigationSplitViewen lugar de apilarse en una navegación. - Los botones de la barra de herramientas se mueven. Los botones que añades a un
WebViewo a unMapcon.toolbar, como el botón Reload de arriba, pasan a la barra vertical cuando compilas con el SDK de iOS 27.1. Dales un símbolo y un título, como recomienda nuestra guía de la barra de herramientas vertical en iPhone Duo. Nuestra guía de la barra de herramientas en iOS 26 explica cómo agrupar estos botones. - Contenido de borde a borde. El ejemplo de Apple aplica
.ignoresSafeArea()a unWebView. En iPhone Duo, la barra vertical añade un margen solo en un lado. La pauta de Apple que recoge nuestra guía de áreas seguras es que los fondos pueden extenderse bajo las barras, pero los elementos interactivos deben quedarse dentro. Una página web está llena de enlaces, así que comprueba que su contenido no queda bajo la barra antes de ignorar ese borde. - El pliegue. Cualquier control superpuesto que dibujes sobre un mapa, como un botón personalizado, debe quedar lejos del pliegue. Nuestra guía de regiones reservadas en el pliegue muestra cómo localizarlo.
Puntos clave
- «Cannot find 'Map' in scope» significa que falta un segundo import: añade
import MapKitjunto aimport SwiftUI. Map,PhotosPickeryWebViewviven en cross-import overlays, módulos ocultos como_MapKit_SwiftUIque solo se cargan cuando un archivo importa ambos frameworks.- Los imports son por archivo, así que cada archivo que usa la vista necesita ambos.
- iOS 26 añade un
WebViewnativo en WebKit. UsaWebView(url:)para páginas sencillas yWebView(page)con unWebPagepara el título, el progreso, la navegación ycallJavaScript. - Mantén un envoltorio de
WKWebViewtrasif #available(iOS 26.0, *)para versiones anteriores. - En iPhone Duo, los elementos de la barra de herramientas sobre mapas y vistas web pasan a la barra vertical, así que dales iconos y mantén el contenido interactivo dentro del área segura.
A continuación, ordena los botones sobre tu mapa o tu vista web con nuestra guía de la barra de herramientas de SwiftUI en iOS 26 y después recorre la checklist para preparar tu app para iPhone Duo. Para ver lo que pueden hacer las apps con el plegado, explora Built for the fold.
Preguntas frecuentes
¿Por qué SwiftUI dice cannot find Map in scope?
Map está declarado en un cross-import overlay de MapKit y SwiftUI, no en SwiftUI. El compilador solo carga ese overlay cuando el mismo archivo importa ambos módulos, así que añade import MapKit junto a import SwiftUI.
¿Qué es un cross-import overlay en Swift?
Es un módulo oculto, como _MapKit_SwiftUI, que añade API que necesitan dos frameworks a la vez. El compilador lo importa automáticamente cuando un archivo de código importa ambos frameworks, así que ninguno de los dos tiene que depender del otro.
¿Basta con importar MapKit en otro archivo?
No. Los imports se aplican por archivo de código, y el overlay se elige a partir de la combinación de imports de cada archivo. Cada archivo que usa Map necesita import SwiftUI e import MapKit.
¿Qué versión de iOS añadió el WebView nativo de SwiftUI?
WebView y su tipo de modelo WebPage son nuevos en iOS 26.0 y forman parte de WebKit. Importa SwiftUI y WebKit para usarlos. En versiones anteriores, mantén un envoltorio UIViewRepresentable alrededor de WKWebView.
¿Cómo ejecuto JavaScript en un WebView de SwiftUI?
Crea un WebPage, pásalo a WebView y llama a try await page.callJavaScript con tu script. El resultado es un valor Any opcional, así que conviértelo al tipo de Swift que esperas.
Fuentes
- WebView · Apple Developer Documentation
- WebPage · Apple Developer Documentation
- Map · Apple Developer Documentation
- PhotosPicker · Apple Developer Documentation
- Meet WebKit for SwiftUI (WWDC25) · Apple Developer
- What's new in SwiftUI (WWDC25) · Apple Developer
- Meet MapKit for SwiftUI (WWDC23) · Apple Developer
- Cross-import overlays · Swift Forums
- Why some Swift types only appear when you import two modules · Sarunw
- SwiftUI has a native WebView in iOS 26 · Sarunw
- SwiftUI WebView · TrozWare (Sarah Reichelt)
- Cannot find Map in scope even though you imported SwiftUI? · @sarunw on X
- Map, PhotosPicker and WebView live in cross-import overlays · @sarunw on X
- SwiftUI finally has a native WebView in iOS 26 · @sarunw on X
- Pair WebView with WebPage · @sarunw on X
Haz que el pliegue forme parte de tu app.
Mostramos apps y juegos que sacan partido de verdad al iPhone Duo. Envíanos la tuya con un enlace al App Store, o mira lo que han creado otros desarrolladores.