【Swift】同名ファイルがMultiple commands produceエラーを出す原因と対策

iOS, Swift

はじめに

こんにちは、株式会社レコチョクの長島です。2022年4月に新卒で入社してiOSアプリの開発などをしています。現在はプロダクト開発第2グループに所属しております。

iOSアプリのVisual Regression Testing(VRT)で使うJSONファイルを用意しているときに、 Multiple commands produceというエラーが出ました。今回はそれが出た原因とどう解決したのかについて紹介します。

なお、VRTに関しては Visual Regression Testingを導入してみた(iOSアプリ) – レコチョクのエンジニアブログという記事で説明されています。ご興味がある方はそちらもご覧ください!

発端

テストの実装準備のため、APIからのレスポンスをモックデータに置き換えるためのJSONファイルを作成していました。APIのレスポンスの種類ごとにフォルダ名を作成し、そのデータの状態をファイル名にして、次のような形で配置しました。

しかし、この構成でビルドを実行したところ、予期せぬコンパイルエラーが発生しました。

エラーが発生している画像

Multiple commands produceを始めて見たので、調査しました。

原因

調べたところ、 Multiple commands produceエラーはビルドシステムの処理の途中で、同じ出力ファイルを複数のビルドコマンドで生成しようとした際に生じるエラーであることがわかりました。
これはAppleの公式ドキュメントに記載されているバンドルの仕様に関連するものです。

バンドルは実行可能なコードとそのコードが使用するリソースを格納する、標準化された階層構造を持つディレクトリである。
(A bundle is a directory with a standardized hierarchical structure that holds executable code and the resources used by that code.)

Xcodeのビルドシステムは、プロジェクト内でターゲットに関連付けられたコード・リソース類をコピーし、それらを統合してバンドルを作成します。この過程においてコピーされたファイル類は1次元のリスト(一列に並べたリスト)として扱われます。

そのため、たとえファイルが別々のディレクトリに存在していても、同じ名前のファイルであればこの処理の途中で名前の衝突が発生してエラーとなります。この処理はBuild Phasesの「Copy Bundle Resources」で確認できます。

Target選択 > Build Phases > Copy Bundle Resourcesを見ると、確かに同名のファイルが存在していることがわかり、これがエラー要因だとわかりました。

同名ファイルがある画像

対策

最も単純で簡単な対策として、ファイル名を一意化することで解決しました。具体的には、ファイル名を次のような形に変更しています。

当然、このような形でファイル名自身が一意になれば、バンドル内での名前衝突は起こらなくなり、上記の Multiple commands produceは発生しなくなりました。

まとめ

Swiftではコンパイル処理とバンドルの仕組み上、同名ファイルがビルド対象になるとエラーになること。そしてその対策としてファイル名は一意に揃えておいたほうが良いということがわかりました。

意識することの少ないSwiftのコンパイル処理やバンドルの仕組みについて調査し、Swiftという言語への理解がより深まりました。今後はこうした部分も含めて、さらに勉強していきます。

参考資料

iOS, Swift