Développeurs
« Cannot find 'Map' in scope » en SwiftUI : corriger les imports de Map et WebView
Corriger « Cannot find 'Map' in scope » en SwiftUI : pourquoi Map, PhotosPicker et WebView exigent un second import, et l'usage de WebView et WebPage sur iPhone Duo.
Par la rédaction AppleDuoPublié le 8 min de lecture
Sur cette page
- Pourquoi SwiftUI affiche-t-il « Cannot find 'Map' in scope » ?
- Qu'est-ce qu'un cross-import overlay en Swift ?
- Quelles vues SwiftUI exigent un second import ?
- Comment utiliser la WebView native de SwiftUI dans iOS 26 ?
- Comment suivre le chargement, la navigation et le JavaScript avec WebPage ?
- Comment prendre en charge les versions d'iOS antérieures à 26 ?
- Les cartes et les vues web demandent-elles quelque chose de particulier sur iPhone Duo ?
- À retenir
Vous ajoutez une carte à une vue SwiftUI, le fichier contient déjà import SwiftUI, et Xcode s'arrête sur « Cannot find 'Map' in scope ». Le type existe, l'orthographe est correcte et la cible de déploiement convient. La même chose se produit avec PhotosPicker et avec la WebView native que SwiftUI a reçue dans iOS 26. La correction tient en un seul import, mais la raison qui se cache derrière explique toute une famille d'erreurs.
Ce guide explique pourquoi l'erreur apparaît, ce qu'est un cross-import overlay, quelles vues exigent un second import, et comment utiliser la WebView d'iOS 26 avec WebPage. Il s'appuie sur la documentation et les sessions WWDC d'Apple, les notes de conception des Swift Forums et les publications du développeur iOS @sarunw. WebView et WebPage sont nouveaux dans iOS 26.0, et certains détails peuvent changer d'une version à l'autre.
Pourquoi SwiftUI affiche-t-il « Cannot find 'Map' in scope » ?
Parce que Map ne fait pas partie de SwiftUI. Comme le dit @sarunw, Map se trouve dans un cross-import overlay : il faut donc à la fois SwiftUI et MapKit. Ce fichier ne compile pas :
import SwiftUI
struct ContentView: View {
var body: some View {
Map() // error: cannot find 'Map' in scope
}
}
Ajoutez une ligne et il compile :
import SwiftUI
import MapKit
struct ContentView: View {
var body: some View {
Map()
}
}
La documentation d'Apple sur Map le classe sous MapKit et le décrit comme une vue SwiftUI. Le nom interne du symbole le place dans un module appelé _MapKit_SwiftUI, qui n'est ni MapKit ni SwiftUI. Ce troisième module, c'est l'overlay.
Deux détails rendent l'erreur plus difficile à repérer. Le message du compilateur ne mentionne pas d'import manquant, et, comme le note @sarunw dans son article sur les cross-import overlays, l'autocomplétion d'Xcode ne peut pas suggérer un type issu d'un module qui n'est pas chargé. Map n'apparaît donc pas non plus dans les suggestions.
Qu'est-ce qu'un cross-import overlay en Swift ?
Un cross-import overlay est un module que le compilateur importe automatiquement lorsqu'un fichier source importe deux modules précis. La discussion de conception sur les Swift Forums décrit des overlays choisis d'après « la combinaison d'imports d'un fichier source ». L'overlay réexporte le premier framework, appelé module déclarant (declaring module), et ajoute des API qui ont aussi besoin du second, appelé module tiers (bystanding module).
Pourquoi ne pas placer Map directement dans SwiftUI ou MapKit ? Map est une View, il a donc besoin de SwiftUI, et il manipule des types MapKit, il a donc besoin de MapKit. Le placer dans l'un des deux frameworks obligerait chaque app qui utilise l'un à charger l'autre. L'overlay ne se charge que lorsqu'un fichier a demandé les deux.
Le mécanisme est visible dans le SDK. Selon @sarunw, un framework doté d'overlays fournit un dossier .swiftcrossimport dans son répertoire Modules, avec un petit fichier par module partenaire :
SDK=$(xcrun --sdk iphonesimulator --show-sdk-path)
cd "$SDK/System/Library/Frameworks/MapKit.framework/Modules"
ls MapKit.swiftcrossimport
cat MapKit.swiftcrossimport/SwiftUI.swiftoverlay
Le fichier SwiftUI.swiftoverlay est un court fichier YAML qui nomme le module overlay, _MapKit_SwiftUI. @sarunw compte 36 cross-import overlays dans le SDK d'iOS 26.
Une conséquence compte au quotidien : les imports se font fichier par fichier. Importer MapKit dans le point d'entrée de votre app ne rend pas Map disponible dans un autre fichier qui n'importe que SwiftUI. Chaque fichier qui utilise la vue a besoin des deux imports.
Quelles vues SwiftUI exigent un second import ?
La règle empirique de @sarunw : identifiez les deux frameworks dont dépend le type, et importez les deux. Voici les cas courants, avec la disponibilité indiquée dans la documentation d'Apple :
| API SwiftUI | Importer aussi | Disponible à partir de |
|---|---|---|
Map, Marker, Annotation | MapKit | iOS 14 (Map) ; iOS 17 pour le contenu de carte |
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 documentation d'Apple indique que chacun de ces symboles appartient à la fois à son framework et à SwiftUI. L'article de @sarunw ajoute d'autres paires, dont ProductView avec StoreKit, .quickLookPreview(_:) avec QuickLook, SceneView et RealityView avec SceneKit et RealityKit, .translationPresentation avec Translation, et .modelContainer avec SwiftData.
Quand vous voyez « Cannot find 'X' in scope » pour un type qui ressemble à du SwiftUI, cherchez donc un second import manquant avant de soupçonner une faute de frappe ou un problème de disponibilité. L'API de construction de contenu de MapKit, avec Marker et Annotation dans Map, est arrivée dans iOS 17 avec la session d'Apple Meet MapKit for SwiftUI.
Comment utiliser la WebView native de SwiftUI dans iOS 26 ?
Avant iOS 26, afficher une page web en SwiftUI imposait d'envelopper WKWebView dans un UIViewRepresentable. Comme le dit @sarunw, SwiftUI dispose enfin d'une WebView native dans iOS 26. La session d'Apple What's new in SwiftUI la présente comme une nouvelle vue SwiftUI pour afficher du contenu web dans votre app, propulsée par WebKit comme Safari.
WebView est elle aussi un type de cross-import overlay. La documentation d'Apple sur WebView la classe sous WebKit et SwiftUI, et ses exemples commencent par les deux imports. Pour une page de conditions d'utilisation ou un article d'aide, l'initialiseur par URL suffit :
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:) accepte une URL optionnelle, et les liens de la page fonctionnent comme dans un navigateur. Apple note qu'une WebView défile comme une ScrollView et accepte scrollBounceBehavior(_:axes:). WebKit ajoute des modificateurs comme webViewBackForwardNavigationGestures(_:), webViewLinkPreviews(_:), webViewTextSelection(_:) et webViewContentBackground(_:). Le modificateur existant findNavigator(isPresented:) ajoute la recherche dans la page, d'après la session d'Apple Meet WebKit for SwiftUI.
Comment suivre le chargement, la navigation et le JavaScript avec WebPage ?
L'initialiseur par URL ne vous dit rien de la page. Quand vous avez besoin du titre, de la progression ou du JavaScript, le conseil de @sarunw est d'associer WebView à WebPage. La documentation d'Apple sur WebPage la décrit comme une classe Observable qui contrôle et gère du contenu web interactif. Conservez-la dans un @State et passez-la à 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")!))
}
}
}
Comme WebPage est observable, le titre et la barre de progression se mettent à jour d'eux-mêmes, sans delegate ni coordinator. La documentation d'Apple précise qu'une WebPage ne peut être liée qu'à une seule WebView à la fois. Voici les membres que vous utiliserez en premier :
| Membre de WebPage | Ce qu'il vous donne |
|---|---|
title, url | Le titre de la page et l'URL actuelle |
isLoading, estimatedProgress | L'état du chargement et la progression de 0 à 1 |
themeColor | La couleur de la balise meta theme-color de la page |
backForwardList | L'historique, dont vous pouvez charger un élément |
load(_:), load(html:baseURL:) | La navigation, qui renvoie une séquence asynchrone d'événements |
callJavaScript(_:arguments:in:contentWorld:) | Exécuter du JavaScript et obtenir un résultat |
Chaque appel à load renvoie une séquence asynchrone d'événements de navigation. La session d'Apple indique qu'une navigation commence par startedProvisionalNavigation, puis se termine ou échoue. Parcourez la séquence avec for try await quand vous devez attendre la fin du chargement d'une page, ou lisez currentNavigationEvent depuis une vue.
Pour le JavaScript, callJavaScript est async throws et renvoie un Any optionnel. Les clés du dictionnaire arguments deviennent des variables locales dans le script :
let heading = try await page.callJavaScript(
"return document.querySelector(selector)?.textContent",
arguments: ["selector": "h1"]
) as? String
Pour autoriser ou bloquer des navigations, conformez un type à WebPage.NavigationDeciding et passez-le à WebPage(configuration:navigationDecider:). La session d'Apple traite aussi des schémas d'URL personnalisés via le protocole URLSchemeHandler.
Comment prendre en charge les versions d'iOS antérieures à 26 ?
WebView et WebPage nécessitent iOS 26 ou ultérieur. Si votre cible de déploiement est plus ancienne, gardez un wrapper WKWebView et choisissez à l'exécution, comme le suggère @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))
}
}
Le fichier a toujours besoin d'import SwiftUI et d'import WebKit. La branche héritée recharge la page chaque fois que SwiftUI met à jour la vue : dans une vraie app, comparez l'URL actuelle avant d'appeler load. Une développeuse, Sarah Reichelt, a constaté que l'exemple de suivi de navigation de la session ne compilait plus dans les bêtas suivantes d'iOS 26 : vérifiez donc les exemples avec votre version d'Xcode.
Les cartes et les vues web demandent-elles quelque chose de particulier sur iPhone Duo ?
Les imports fonctionnent de la même façon sur tous les iPhone, mais l'iPhone Duo change l'espace dans lequel ces vues s'affichent.
- Plus de place une fois ouvert. L'écran intérieur renvoie une largeur et une hauteur regular dans les deux orientations, comme l'explique notre guide des size classes de l'iPhone Duo. Une carte ou une vue web peut s'afficher à côté d'une liste dans un
NavigationSplitViewau lieu d'être poussée sur une pile. - Les boutons de la barre d'outils se déplacent. Les boutons que vous attachez à une
WebViewou à uneMapavec.toolbar, comme le bouton Reload ci-dessus, passent dans la barre verticale quand vous compilez avec le SDK iOS 27.1. Donnez-leur un symbole et un titre, comme le recommande notre guide de la barre d'outils verticale de l'iPhone Duo. Notre guide de la barre d'outils d'iOS 26 explique comment regrouper ces boutons. - Contenu bord à bord. L'exemple d'Apple applique
.ignoresSafeArea()à uneWebView. Sur iPhone Duo, la barre verticale ajoute une marge d'un seul côté. La recommandation d'Apple, reprise dans notre guide des safe areas, est que les arrière-plans peuvent passer sous les barres mais que les éléments interactifs doivent rester à l'intérieur. Une page web est pleine de liens : vérifiez que son contenu reste à l'écart de la barre avant d'ignorer ce bord. - Le pli. Les commandes que vous superposez à une carte, comme un bouton personnalisé, doivent rester à l'écart du pli. Notre guide des régions réservées du pli explique comment le localiser.
À retenir
- « Cannot find 'Map' in scope » signale un second import manquant : ajoutez
import MapKità côté d'import SwiftUI. Map,PhotosPickeretWebViewse trouvent dans des cross-import overlays, des modules cachés comme_MapKit_SwiftUIqui ne se chargent que lorsqu'un fichier importe les deux frameworks.- Les imports se font fichier par fichier : chaque fichier qui utilise la vue a besoin des deux.
- iOS 26 ajoute une
WebViewnative dans WebKit. UtilisezWebView(url:)pour les pages simples etWebView(page)avec uneWebPagepour le titre, la progression, la navigation etcallJavaScript. - Gardez un wrapper
WKWebViewderrièreif #available(iOS 26.0, *)pour les cibles plus anciennes. - Sur iPhone Duo, les éléments de barre d'outils au-dessus des cartes et des vues web passent dans la barre verticale : donnez-leur des icônes et gardez le contenu interactif dans la safe area.
Ensuite, rangez les boutons au-dessus de votre carte ou de votre vue web grâce à notre guide de la barre d'outils SwiftUI dans iOS 26, puis parcourez la checklist de préparation à l'iPhone Duo. Pour voir ce que les apps peuvent faire avec le pli, parcourez Built for the fold.
Questions fréquentes
Pourquoi SwiftUI affiche-t-il « Cannot find 'Map' in scope » ?
Map est déclaré dans un cross-import overlay de MapKit et SwiftUI, pas dans SwiftUI lui-même. Le compilateur ne charge cet overlay que si le même fichier importe les deux modules : ajoutez donc import MapKit à côté d'import SwiftUI.
Qu'est-ce qu'un cross-import overlay en Swift ?
C'est un module caché, comme _MapKit_SwiftUI, qui ajoute des API ayant besoin de deux frameworks à la fois. Le compilateur l'importe automatiquement lorsqu'un fichier source importe les deux frameworks, si bien qu'aucun des deux n'a à dépendre de l'autre.
Importer MapKit dans un autre fichier suffit-il ?
Non. Les imports s'appliquent fichier par fichier, et l'overlay est choisi d'après la combinaison d'imports de chaque fichier. Chaque fichier qui utilise Map a besoin à la fois d'import SwiftUI et d'import MapKit.
Quelle version d'iOS a introduit la WebView native de SwiftUI ?
WebView et son type modèle WebPage sont nouveaux dans iOS 26.0 et font partie de WebKit. Importez SwiftUI et WebKit pour les utiliser. Sur les versions antérieures, gardez un wrapper UIViewRepresentable autour de WKWebView.
Comment exécuter du JavaScript dans une WebView SwiftUI ?
Créez une WebPage, passez-la à WebView, puis appelez try await page.callJavaScript avec votre script. Le résultat est une valeur Any optionnelle : convertissez-la dans le type Swift attendu.
Sources
- 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
Faites du pli une partie de votre app.
Nous présentons les apps et les jeux qui exploitent vraiment l’iPhone Duo. Envoyez-nous la vôtre avec un lien vers l’App Store, ou découvrez ce que d’autres ont créé.