PC パソコン

Xcode「Module dependency cycle: UIKit.swiftmodule → ~ → UIKit.swiftmodule」の原因と解決方法

Xcodeで「Module dependency cycle: UIKit.swiftmodule → … → UIKit.swiftmodule」と表示される場合、明示的モジュールの依存関係スキャンが循環を検出しています。UIKit自体を修正するのではなく、エラーに表示された経路を読み、プロジェクトのFramework、Bridging Header、Module Map、公開ヘッダーの相互importを解消します。

エラーの意味

Module dependency cycle:
UIKit.swiftmodule
→ MyFramework.swiftmodule
→ SomeClangModule.pcm
→ UIKit.swiftmodule

Xcode 26ではSwift Explicit ModulesがSwiftターゲットの標準になりました。コンパイラはビルド前に依存モジュールを走査して個別に構築するため、従来は暗黙的importや偶然のビルド順で隠れていた循環が明確なエラーとして現れることがあります。

発生しやすい条件

  • Framework AがFramework Bをimportし、BもAをimportしている
  • Bridging HeaderがSwift生成ヘッダー(ProductModuleName-Swift.h)をimportしている
  • Umbrella Headerや公開ヘッダーが不要なUIKit・自社Frameworkをimportしている
  • module.modulemapがPrivate Headerや別モジュールのUmbrella Headerまで含んでいる
  • C/Objective-Cの公開ヘッダー内に実装専用依存関係が露出している
  • Xcode 26への更新後、Explicit Modulesで依存関係が厳密に検査された

推奨する解決手順

1. 循環経路を最後まで読む

Issue NavigatorまたはBuild Logで「Module dependency cycle」の全経路を展開します。先頭のUIKitではなく、同じモジュールへ戻る直前にある自社Framework、Clang Module、PCMを探します。

UIKit.swiftmoduleが経路の両端に表示されても、UIKitが原因とは限りません。循環へUIKitを再導入したプロジェクト側ヘッダーやModule Mapが重要です。

2. ターゲット依存関係を一方向にする

A→B→Aとなっている場合は、共通型やプロトコルを第三の小さなモジュールへ移します。

Before: FeatureA → FeatureB → FeatureA
After:  FeatureA → SharedInterfaces ← FeatureB

Target Dependencies、Link Binary With Libraries、Swift Packageのtarget dependenciesも確認し、不要な逆向き依存を削除します。

3. Bridging Headerを確認する

Bridging Headerから自ターゲットの-Swift.hをimportしないでください。Objective-CからSwiftを使う場合はObjective-Cの実装ファイル側で生成ヘッダーをimportし、Bridging HeaderにはSwiftから必要なObjective-Cヘッダーだけを置きます。

// MyProject-Bridging-Header.h
// NG: #import "MyProject-Swift.h"
#import "LegacyAPI.h"

4. 公開ヘッダーとModule Mapを最小化する

  • 公開ヘッダーで不要な#importを削除し、可能なら前方宣言を使う
  • 実装だけで使うヘッダーはPublicからProject/Privateへ移す
  • Umbrella Headerに別Frameworkの包括ヘッダーを無条件で入れない
  • カスタムModule Mapのumbrella、header、exclude headerを見直す
@class SomeViewController;
@protocol SomeService;

5. 修正後にクリーンな依存グラフで確認する

  1. Product > Clean Build Folderを実行する
  2. Swift Packageを再解決する
  3. DerivedDataを削除してClean Buildを行う
  4. CIでも同じXcode版でビルドする

一時的な代替策

Xcode 26のリリースノートでは、重大な問題がある場合にExplicit Modulesを一時的に無効化できると案内されています。

SWIFT_ENABLE_EXPLICIT_MODULES = NO

これは移行用の回避策です。依存関係の循環自体を直すものではなく、将来のXcodeで同じ問題が再発する可能性があります。まず問題ターゲットに限定し、恒久対応としてヘッダーとモジュール構造を修正してください。

確認方法

  1. Clean Buildでdependency cycleが出ない
  2. Explicit Modulesを有効に戻してビルドできる
  3. Simulator・実機・Archiveのすべてが成功する
  4. 別MacまたはCIの空キャッシュ環境でも成功する

注意点

モジュール名を変更したり、検索パスを追加したりして循環を隠すと、異なるモジュールが同じヘッダーを取り込む問題につながります。完全な経路を保存し、最初にプロジェクト側へ戻るimportを取り除くのが安全です。

2026年9月16日時点で、すべてのUIKit.swiftmodule循環に共通するXcode修正版はAppleから示されていません。Xcode 26のExplicit Modules標準化を前提に、個々の依存グラフを修正する必要があります。

まとめ

このエラーはUIKitの故障ではなく、モジュール依存関係が一周していることを示します。エラー経路から自社モジュールを特定し、双方向ターゲット依存、Bridging Header、公開ヘッダー、Module Mapを整理してください。Explicit Modulesの無効化は、恒久修正までの限定的な回避策として扱います。

参考資料