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 と書いてました。
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 のようにアクセスしたかったので、以下のようにエクステンションを追加しました。
extension Bundle {
static var current: Bundle {
class DummyClass {}
return Bundle(for: type(of: DummyClass()))
}
}
// 使う時は Bundle.current でアクセスできます。
テキトーなクラスを作って、それを元に Bundle を生成することで、アクセスしたファイルのある Bundle になります。
さいごに
1プロジェクトで1回しかやらないので、毎回忘れちゃう。笑



コメント