CleanArchitecuture を導入しており、Infra や Domain などの層を Embedded Framework を使って分けていました。
その際、Infra でテキストファイルを開こうとしたらエラーになり、「あぁバンドルバンドル…」と思いつつ、どうやったっけ??ってなるので、自分用も兼ねて対処方法を載せます。
開発環境(前提条件)
・Xcode14.0(2022年10月24日再確認済み)
・Swift5
・プロジェクト内で Embedded Framework を利用している
そもそも Bundle とは
ディスク上のバンドルディレクトリに格納されているコードとリソースを表現したものです。
Xcode でいうと TARGET → Build Phases → Copy Bundle Resources に含まれているもので、普通に開発してたら Storyboard や Assets 等もここに追加されていきます。
これらのファイルはお馴染みの Bundle.main でアクセスできます。
細かい説明は本題から外れるので、詳細が気になる方は公式ドキュメントをご覧ください。
問題となるのは
データ関連は全て Infra から取得したかったので、テキストファイルもそこに置きました。
それを文字列にして取得したんですが、無意識に Bundle.main と書いてました。
1 2 3 4 5 6 7 8 9 10 |
guard let url = Bundle.main.url(forResource: "filename", withExtension: "txt") else { fatalError("テキストファイルないやんけ") } do { let text = try String(contentsOfFile: url.path, encoding: .utf8) // ...テキトーな処理 } catch { print(error.localizedDescription) } |
これ FatalError になります。
Bundle.main のディレクトリは以下のようになります。
/private/var/containers/Bundle/Application/********-****-****-****-************/Sample.app
そして、Embedded Framework で Infra を追加した場合のディレクトリは、Sample.app の直下に /Frameworks/Infra.framework というような構成で追加されます。
そのため、Infra にファイルを追加したとしても、Bundle.main とはパスが違うってわけです。
解決方法
僕は Infra の中で Bundle.main のようにアクセスしたかったので、以下のようにエクステンションを追加しました。
1 2 3 4 5 6 7 |
extension Bundle { static var current: Bundle { class DummyClass {} return Bundle(for: type(of: DummyClass())) } } // 使う時は Bundle.current でアクセスできます。 |
テキトーなクラスを作って、それを元に Bundle を生成することで、アクセスしたファイルのある Bundle になります。
さいごに
1プロジェクトで1回しかやらないので、毎回忘れちゃう。笑
コメント