Skip to content
すべての記事

SwiftUI の「Cannot find 'Map' in scope」を解決

SwiftUI の「Cannot find 'Map' in scope」の原因と直し方。Map や WebView に2つ目の import が必要な理由と、iPhone Duo での WebView の使い方を解説。

AppleDuo 編集部公開 15分で読めます

ほかの言語:EnglishDeutschEspañolFrançaisTürkçe

このページの内容
  1. SwiftUI で「Cannot find 'Map' in scope」と表示されるのはなぜ?
  2. Swift のクロスインポートオーバーレイとは?
  3. 2つ目の import が必要な SwiftUI のビューは?
  4. iOS 26 で SwiftUI のネイティブの WebView を使うには?
  5. WebPage で読み込み、ナビゲーション、JavaScript を扱うには?
  6. iOS 26 より前のバージョンに対応するには?
  7. iPhone Duo で地図や Web ビューに特別な対応は必要?
  8. まとめ

SwiftUI のビューに地図を追加すると、ファイルにはすでに import SwiftUI があるのに、Xcode が 「Cannot find 'Map' in scope」 で止まってしまう。型は存在し、綴りも正しく、デプロイメントターゲットにも問題はありません。同じことは PhotosPicker や、iOS 26 で SwiftUI に加わったネイティブの WebView でも起こります。解決策は import を1行追加するだけですが、その理由を知ると、同じ系統のエラーをまとめて理解できます。

このガイドでは、エラーが出る理由、クロスインポートオーバーレイとは何か、2つ目の import が必要なビュー、そして iOS 26 の WebView を WebPage と組み合わせて使う方法を解説します。内容は Apple のドキュメントと WWDC のセッション、Swift Forums の設計に関する議論、iOS デベロッパ @sarunw の投稿に基づいています。WebView と WebPage は iOS 26.0 の新機能で、リリース間で詳細が変わる可能性があります。

SwiftUI で「Cannot find 'Map' in scope」と表示されるのはなぜ?

Map が SwiftUI に含まれていないからです。@sarunw の言葉を借りれば、「Map はクロスインポートオーバーレイにあるので、SwiftUI と MapKit の両方が必要です。」次のファイルはビルドに失敗します。

import SwiftUI

struct ContentView: View {
    var body: some View {
        Map() // error: cannot find 'Map' in scope
    }
}

1行追加すればビルドできます。

import SwiftUI
import MapKit

struct ContentView: View {
    var body: some View {
        Map()
    }
}

Apple の Map のドキュメントでは、Map は MapKit の下に分類され、SwiftUI のビューとして説明されています。シンボルの内部名を見ると、Map は _MapKit_SwiftUI というモジュールに属しており、これは MapKit でも SwiftUI でもありません。この3つ目のモジュールがオーバーレイです。

このエラーに気づきにくい理由が2つあります。コンパイラのメッセージは import が足りないことに触れていません。また、@sarunw がクロスインポートオーバーレイについての記事で指摘しているように、Xcode のオートコンプリートは読み込まれていないモジュールの型を候補に出せません。そのため、Map は補完候補にも表示されないのです。

Swift のクロスインポートオーバーレイとは?

クロスインポートオーバーレイとは、ソースファイルが特定の2つのモジュールを import したときに、コンパイラが自動的に import するモジュールのことです。Swift Forums の設計に関する議論では、オーバーレイは「ソースファイル内の import の組み合わせ」から選ばれると説明されています。オーバーレイは1つ目のフレームワーク(declaring module)を再エクスポートし、2つ目のフレームワーク(bystanding module)も必要とする API を追加します。

なぜ Map を SwiftUI か MapKit に直接入れないのでしょうか。Map は View なので SwiftUI が必要で、MapKit の型と連携するので MapKit も必要です。どちらかのフレームワークに入れると、一方を使うすべてのアプリがもう一方も取り込むことになります。オーバーレイなら、ファイルが両方を求めたときにだけ読み込まれます。

この仕組みは SDK の中で確認できます。@sarunw によると、オーバーレイを持つフレームワークは Modules ディレクトリに .swiftcrossimport フォルダを含み、相手のモジュールごとに小さなファイルが1つずつ入っています。

SDK=$(xcrun --sdk iphonesimulator --show-sdk-path)
cd "$SDK/System/Library/Frameworks/MapKit.framework/Modules"
ls MapKit.swiftcrossimport
cat MapKit.swiftcrossimport/SwiftUI.swiftoverlay

SwiftUI.swiftoverlay は短い YAML ファイルで、オーバーレイのモジュール名 _MapKit_SwiftUI を指定しています。@sarunw の数えでは、iOS 26 SDK には36のクロスインポートオーバーレイがあります。

日々の開発で重要な影響が1つあります。import はファイルごとだということです。アプリのエントリポイントで MapKit を import しても、SwiftUI しか import していない別のファイルで Map が使えるようにはなりません。そのビューを使うファイルごとに、両方の import が必要です。

2つ目の import が必要な SwiftUI のビューは?

@sarunw の目安はこうです。その型が依存する2つのフレームワークを見つけて、両方を import すること。よく使うものを、Apple のドキュメントにある利用可能バージョンとともにまとめます。

SwiftUI の API追加で import利用可能
Map、Marker、AnnotationMapKitiOS 14(Map)、地図コンテンツは iOS 17
PhotosPickerPhotosUIiOS 16
WebViewWebKitiOS 26
VideoPlayerAVKitiOS 14
SubscriptionStoreViewStoreKitiOS 17
SpriteViewSpriteKitiOS 14
SignInWithAppleButtonAuthenticationServicesiOS 14

Apple のドキュメントでは、これらのシンボルはそれぞれ自身のフレームワークと SwiftUI の両方に属するものとして記録されています。@sarunw の記事にはさらに多くの組み合わせが挙げられています。StoreKit との ProductView、QuickLook との .quickLookPreview(_:)、SceneKit や RealityKit との SceneView と RealityView、Translation との .translationPresentation、SwiftData との .modelContainer などです。

ですから、SwiftUI らしい型で「Cannot find 'X' in scope」が出たら、綴りの間違いや利用可能バージョンの問題を疑う前に、2つ目の import が足りないかどうかを確認しましょう。Map の中に Marker や Annotation を書く MapKit のコンテンツビルダー API は、Apple のセッション「Meet MapKit for SwiftUI」とともに iOS 17 で登場しました。

iOS 26 で SwiftUI のネイティブの WebView を使うには?

iOS 26 より前は、SwiftUI で Web ページを表示するには WKWebView を UIViewRepresentable で包む必要がありました。@sarunw の言葉では、「SwiftUI に iOS 26 でようやくネイティブの WebView が加わりました。」Apple のセッション「What's new in SwiftUI」では、Safari と同じく WebKit を基盤とする「アプリで Web コンテンツを表示するための新しい SwiftUI ビュー」と紹介されています。

WebView もクロスインポートオーバーレイの型です。Apple の WebView のドキュメントでは WebKit と SwiftUI の下に記載され、サンプルは両方の import から始まっています。利用規約のページやヘルプ記事なら、URL のイニシャライザだけで十分です。

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:) はオプショナルの URL を受け取り、ページ内のリンクはブラウザと同じように機能します。Apple によると、WebView は ScrollView のようにスクロールし、scrollBounceBehavior(_:axes:) を受け付けます。WebKit は webViewBackForwardNavigationGestures(_:)、webViewLinkPreviews(_:)、webViewTextSelection(_:)、webViewContentBackground(_:) などのモディファイアを追加します。Apple のセッション「Meet WebKit for SwiftUI」によると、既存の findNavigator(isPresented:) モディファイアでページ内検索も追加できます。

WebPage で読み込み、ナビゲーション、JavaScript を扱うには?

URL のイニシャライザでは、ページについて何も知ることができません。タイトル、進捗、JavaScript が必要なときの @sarunw の助言は、「WebView を WebPage と組み合わせる」ことです。Apple の WebPage のドキュメントでは、インタラクティブな Web コンテンツを制御・管理する Observable クラスと説明されています。@State で保持して 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")!))
        }
    }
}

WebPage は監視可能なので、デリゲートもコーディネーターもなしに、タイトルとプログレスバーが自動で更新されます。Apple のドキュメントによると、WebPage は同時に1つの WebView にしかバインドできません。最初に使うことになるメンバーは次のとおりです。

WebPage のメンバー得られるもの
title、urlページのタイトルと現在の URL
isLoading、estimatedProgress読み込み状態と 0 から 1 までの進捗
themeColorページの theme-color メタタグの色
backForwardList履歴。項目を指定して読み込める
load(_:)、load(html:baseURL:)ナビゲーション。イベントの非同期シーケンスを返す
callJavaScript(_:arguments:in:contentWorld:)JavaScript を実行して結果を受け取る

load を呼び出すたびに、ナビゲーションイベントの非同期シーケンスが返されます。Apple のセッションによると、ナビゲーションは startedProvisionalNavigation で始まり、その後完了するか失敗します。ページの読み込み完了を待つ必要がある場合は for try await でシーケンスを反復し、ビューからは currentNavigationEvent を読み取ります。

JavaScript については、callJavaScript は async throws で、オプショナルの Any を返します。arguments 辞書のキーは、スクリプト内のローカル変数になります。

let heading = try await page.callJavaScript(
    "return document.querySelector(selector)?.textContent",
    arguments: ["selector": "h1"]
) as? String

ナビゲーションを許可またはブロックするには、型を WebPage.NavigationDeciding に準拠させ、WebPage(configuration:navigationDecider:) に渡します。Apple のセッションでは、URLSchemeHandler プロトコルによるカスタム URL スキームも扱っています。

iOS 26 より前のバージョンに対応するには?

WebView と WebPage には iOS 26 以降が必要です。デプロイメントターゲットがそれより低い場合は、@sarunw が勧めているように、WKWebView のラッパーを残して実行時に選びます。

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))
    }
}

このファイルにも import SwiftUI と import WebKit の両方が必要です。従来の経路は SwiftUI がビューを更新するたびに再読み込みするので、実際のアプリでは load を呼ぶ前に現在の URL と比較してください。デベロッパの Sarah Reichelt は、セッションのナビゲーション追跡のサンプルが iOS 26 の後のベータでコンパイルできなくなったことを報告しているので、サンプルは自分の Xcode のバージョンで確認しましょう。

iPhone Duo で地図や Web ビューに特別な対応は必要?

import はどの iPhone でも同じように機能しますが、iPhone Duo ではこれらのビューが置かれるスペースが変わります。

  • 開くと広くなる。 内側ディスプレイは、iPhone Duo のサイズクラスのガイドで説明しているように、どちらの向きでも幅と高さが regular です。地図や Web ビューは、スタックにプッシュする代わりに、NavigationSplitView でリストの隣に置けます。
  • ツールバーのボタンが移動する。 上の Reload ボタンのように、.toolbar で WebView や Map に付けたボタンは、iOS 27.1 SDK でビルドすると縦向きバーに移動します。iPhone Duo の縦向きツールバーのガイドで勧めているように、シンボルとタイトルを与えましょう。これらのボタンのグループ化については iOS 26 のツールバーのガイドで解説しています。
  • 端から端までのコンテンツ。 Apple のサンプルでは WebView に .ignoresSafeArea() を適用しています。iPhone Duo では、縦向きバーは片側にだけインセットを追加します。セーフエリアのガイドで紹介している Apple のガイダンスでは、背景はバーの下まで広げてもよいものの、インタラクティブな要素は内側に留めるべきとされています。Web ページはリンクだらけなので、その端を無視する前に、コンテンツがバーにかからないことを確認してください。
  • 折り目。 カスタムボタンなど、地図の上に重ねて描くコントロールは、折り目から離して配置しましょう。その位置を取得する方法は、折り目の予約領域のガイドで紹介しています。

まとめ

  • 「Cannot find 'Map' in scope」は2つ目の import が足りないことを意味します。import SwiftUI の隣に import MapKit を追加しましょう。
  • Map、PhotosPicker、WebView はクロスインポートオーバーレイにあります。これは _MapKit_SwiftUI のような隠れたモジュールで、1つのファイルが両方のフレームワークを import したときにだけ読み込まれます。
  • import はファイルごとなので、そのビューを使うすべてのファイルに両方が必要です。
  • iOS 26 では WebKit にネイティブの WebView が加わりました。シンプルなページには WebView(url:) を、タイトル、進捗、ナビゲーション、callJavaScript が必要なら WebPage と組み合わせた WebView(page) を使います。
  • 古いターゲット向けには、if #available(iOS 26.0, *) の裏に WKWebView のラッパーを残しておきましょう。
  • iPhone Duo では、地図や Web ビューの上のツールバーのアイテムが縦向きバーに移動するので、アイコンを与え、インタラクティブなコンテンツはセーフエリアの内側に留めましょう。

次は、iOS 26 の SwiftUI ツールバーのガイドで地図や Web ビューの上のボタンを整え、iPhone Duo 対応チェックリストをひととおり実施してください。アプリが折りたたみで何をできるかは、Built for the fold でご覧いただけます。

よくある質問

SwiftUI で「Cannot find 'Map' in scope」と表示されるのはなぜ?

Map は SwiftUI 自体ではなく、MapKit と SwiftUI のクロスインポートオーバーレイで宣言されているからです。コンパイラがこのオーバーレイを読み込むのは同じファイルで両方のモジュールを import した場合だけなので、import SwiftUI と一緒に import MapKit を追加してください。

Swift のクロスインポートオーバーレイとは?

_MapKit_SwiftUI のような隠れたモジュールで、2つのフレームワークを同時に必要とする API を追加します。ソースファイルが両方のフレームワークを import するとコンパイラが自動的に import するので、どちらのフレームワークももう一方に依存する必要がありません。

別のファイルで MapKit を import するだけで足りますか?

足りません。import はソースファイルごとに適用され、オーバーレイは各ファイルの import の組み合わせから選ばれます。Map を使うすべてのファイルに、import SwiftUI と import MapKit の両方が必要です。

SwiftUI のネイティブの WebView はどの iOS バージョンで追加されましたか?

WebView とそのモデル型である WebPage は iOS 26.0 の新機能で、WebKit に含まれています。使うには SwiftUI と WebKit を import します。それより前のバージョンでは、WKWebView を包む UIViewRepresentable のラッパーを残しておきましょう。

SwiftUI の WebView で JavaScript を実行するには?

WebPage を作成して WebView に渡し、スクリプトを指定して try await page.callJavaScript を呼び出します。結果はオプショナルの Any 値なので、想定する Swift の型にキャストしてください。

出典

  1. WebView · Apple Developer Documentation
  2. WebPage · Apple Developer Documentation
  3. Map · Apple Developer Documentation
  4. PhotosPicker · Apple Developer Documentation
  5. Meet WebKit for SwiftUI (WWDC25) · Apple Developer
  6. What's new in SwiftUI (WWDC25) · Apple Developer
  7. Meet MapKit for SwiftUI (WWDC23) · Apple Developer
  8. Cross-import overlays · Swift Forums
  9. Why some Swift types only appear when you import two modules · Sarunw
  10. SwiftUI has a native WebView in iOS 26 · Sarunw
  11. SwiftUI WebView · TrozWare (Sarah Reichelt)
  12. Cannot find Map in scope even though you imported SwiftUI? · @sarunw on X
  13. Map, PhotosPicker and WebView live in cross-import overlays · @sarunw on X
  14. SwiftUI finally has a native WebView in iOS 26 · @sarunw on X
  15. Pair WebView with WebPage · @sarunw on X

折りたたみを、アプリの一部に。

AppleDuo は iPhone Duo を本当に活かしたアプリとゲームを紹介しています。App Store へのリンクを添えて送ってください。ほかの開発者の作品も見られます。

[email protected]