シミュレータでのデバック時やXcode previewsを利用する際に、差分管理の都合上、プロジェクトにリソースを追加せずにデバッグしたいケースがあります。
そのような場合に、リソースのロードにローカルのパスを参照する必要があるため、Xcodeのプロジェクトルートをコードから探る必要が生じます。
ということでDEBUG
onlyで、プロジェクトルートを辿る方法を考えてみます。
(今回はSRCROOT
を使っていますが、PROJECT_DIR
などでも同様です。)
ビルド時にスクリプトでInfo.plistに書き込む
PlistBuddy
を使って、Info.plist
に書き込む方法です。
Build PhasesのCopy Bundle Resourcesの後にスクリプトを追加して、.app
配下のInfo.plist
に項目を追加します。
(プロジェクト内のInfo.plist
には項目は追加されません)
if [ "${CONFIGURATION}" = "Debug" ]; then /usr/libexec/PlistBuddy -c "Add :RootDir string ${SRCROOT}" "${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH}" fi
PlistBuddy
で書き込む際に、ENABLE_USER_SCRIPT_SANDBOXING
をNO
にする必要があります。
Swiftからは、Bundle.main.infoDictionary
で取得できます。
let projectRootPath = Bundle.main.infoDictionary?["RootDir"] as? String
SRCROOT
以外にも、gitで管理している場合はそちらを使うことができます。
filePathマクロを使う
#filePath
マクロを使うことで、あるファイルのパスからプロジェクトルートを探す方法です。
ファイルの置き場所とプロジェクトルートの相対パスに処理が依存するので、ファイルの移動の際に注意する必要があります。
let fileUrl = URL(filePath: #filePath) let components = fileUrl.pathComponents.dropLast().dropFirst() // 相対パスに応じて加工 let projectRootPath = components.joined(separator: "/")
リソース置き場に上記の内容を含んだファイルを置いておけば、相対パスの考慮が必要なくなります。
ObjC経由でpreprocessor macroを使う
Swiftからは直接preprocessor macroの値を参照することはできないですが、Objective-Cで定数として定義し直して利用する方法もあります。
Build SettingsのApple Clang - Preperocessingから、Preprocessor MacrosでROOTDIR=$(SRCROOT)
のように定義します。
Objective-Cの適当なヘッダーに定数を定義して、Bridging-Headerを介してSwiftから扱います。
#import <Foundation/Foundation.h> #ifdef DEBUG static NSString *const projectRootPath = @OS_STRINGIFY(ROOTDIR); #endif
SwiftからはprojectRootPath
で参照できます。