【Xcode/iOS】マルチモジュール化とは?ライブラリ/フレームワーク/SPMへの切り出し

この記事からわかること
- Xcode/iOSアプリでマルチモジュール化を行う方法
- ライブラリとフレームワークの違い
- SPMを使ったライブラリへの切り出し方法
index
[open]
\ アプリをリリースしました /
環境
- Xcode:16.3
- iOS:18.0
- Swift:5.9
- macOS:Sequoia 15.4
マルチモジュール化とは?
アプリ開発を行なっていく上でアプリの規模が大きくなればなるほどコード量も増加し、コード自体も複雑化していきます。これを1つのモジュール(ターゲット)として管理(モノシリック※)しようとするとコード間の密結合や依存関係の肥大化が発生しやすくなり、いくつか悩みの種が生まれてきます。
※ モノシリックとは「一枚岩のような」という意味の英単語でソフトウェア開発においても分離がされておらず一体化した1つのモジュールで構成されている設計のことを指します。
モノシリック構造のアプリの悩みの種
- 再利用性の低下
- ビルド時間の増加
- チーム開発の効率低下
- テストに不向きな構造
上記のような悩みを解決するための手段の1つが「マルチモジュール化」です。これはその名の通り、複数のモジュール(=部品)に分割し、それらを組み合わせることでアプリを構成する設計手法です。このアプローチは「関心の分離(Separation of Concerns)」の考え型に基づいており機能やドメイン、レイヤーごとに責務を分割することでコードの結び付きを軽減(=疎結合)し、保守性や再利用性を高めることができます。
マルチモジュール化のメリット
- 再利用性の向上
- ビルド時間の短縮
- テスト向きな構造
モジュールごとに切り出すことにより、機能が分割されることで別アプリへの流用や、テスト向きな設計、またXcodeではモジュールのビルドにキャッシュも働くのでビルド時間の短縮も期待できます。
マルチモジュール化のデメリット
ただマルチモジュール化もメリットだけではありません。
マルチモジュール化のデメリット
- 設計段階のハードルの高さ(分割単位など)
- 抽象度が高くなるが故の煩雑さ
責務を分割と言ってもどの単位で分けていくのが効率が良いかは個人の考え方やプロジェクトに依存する部分だと思います。またモジュール化するための作業コストも発生するので小さいプロジェクトなどでは導入することが必ずしも良い影響を与えるわけではない場合もあります。
またモジュール間の依存を避けるために抽象的なインターフェースが必要になってきます。その分具体的なコードを見つけづらかったり、ロジックの中身の把握に時間がかかってしまうなど可読性の低下に直結してしまう可能性もあります。
モジュールとは?
iOSアプリ開発における「モジュール」はビルドターゲットやライブラリ、フレームワークなどになります。それぞれに名前空間が指定され別のモジュールからのアクセス制御が働いています。
そのためマルチモジュール化を行うための手段がライブラリやフレームワークへの切り出しです。独立できる機能をライブラリやフレームワークとして切り出すことで、モジュール内だけで留めておいた方が良いコードなどをモジュール内に隠蔽することができるため、全体の見通しや可読性も向上します。ただライブラリやフレームワークにも種類があります。
Xcodeにおけるライブラリとフレームワークの違い
ただライブラリとフレームワークは似ているので先に違いをまとめておきます。種類としては以下の4通りがあります。ここでいう「静的(Static) / 動的(Dynamic)」の違いはライブラリ/フレームワークを読み込んでアプリに統合するタイミングの違いになります。
- 静的(Static)ライブラリ
- 動的(Dynamic)ライブラリ
- 静的(Static)フレームワーク
- 動的(Dynamic)フレームワーク
静的はビルド時のリンクフェーズで読み込まれアプリに取り込まれます。一方動的はアプリ起動してから実際にその機能が使用されるタイミングで読み込まれます。ただこれはmacOSのみでiOSアプリでは起動時に読み込まれるようです。
ライブラリとは?
ライブラリとはシンプルにいうとコードの集合体です。特定の機能や処理などを定義しライブラリという形で切り出すことで再利用しやすいようにまとめられています。
ビルド時にライブラリが読み込まれると.a
形式のバイナリファイルに変換されアプリに取り込まれます。.a
ファイルにはリソース(画像など)を含めることができないのでフレームワークを使用する必要があります。
フレームワークとは?
フレームワークとはシンプルにいうとコード + メタ情報 + リソースの集合体です。基本的な役割や目的はライブラリと変わりませんがライブラリとは異なりバンドルとして扱われます。バンドルとして扱われることでバンドルIDの指定も必要になります。
ビルド時にフレームワークが読み込まれると.framework
というディレクトリ構造のバンドル形式になります。この中には.a
ファイルやヘッダー、リソースなどが含まれます。
Swiftコードをモジュール化する方法
実際にXcodeで開発中のプロジェクト内でモジュール化を行う方法を紹介していきます。
- Dynamic Framework
- Static Library
- Swift Package Manager(SPM)
Dynamic Framework
XcodeからFrameworkを作成するには上部メニュー「File」>「New」>「Target...」からFramework」を選択します。作成する際はバンドルIDも一緒に決める必要があります。またデフォルトで生成されるFrameworkはDynamic Frameworkです。Staticに変更したい場合は「Build Settings」>「Mach-O Type」>「Static Framework」に変更する必要があるようです。

Frameworkを追加すると以下(TestFramework)のようなファイル群が自動で追加されます。

Static Library
XcodeからStatic Libraryを作成するには上部メニュー「File」>「New」>「Target...」から「Static Library」を選択します。
Static Libraryを追加すると以下(TestLibrary)のようなファイル群が自動で追加されます。

詳細な実装方法は以下の記事を参考にしてください。
Swift Package Manager(SPM)
Swift Package Manager(SPM)のパッケージとして切り出す方法もあります。
参考文献
Medium:Libraries, frameworks, swift packages… What’s the difference?
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。