iOS向けのアプリケーションやライブラリで画像やローカライズファイルなどのリソースを使うとき,bundleという仕組みを利用します.
bundleはアプリケーションやライブラリに組み込まれ,実行時に各リソースファイルとの橋渡しをします.
例えば,ローカライズに使うNSLocalizedString
マクロはこのように定義されています.
#define NSLocalizedString(key, comment) \ [[NSBundle mainBundle] localizedStringForKey:(key) value:@"" table:nil]
[NSBundle mainBundle]
は実行中のアプリケーションbundleを返します.
tableが実際に使用されるローカライズファイルですが,nilだとデフォルトのLocalizable.stringsが利用されます.
NSLocalizedStrings
はここから定義された文字列を探し,返すというわけです.
ここからはリソースにアクセスするためにbundleの仕組みが利用されていることがよくわかります.
顕在化する[NSBundle mainBundle]
リスク
長らくiOSアプリではライブラリの組み込みにリンクでは無く,アプリケーションへ直接組み込むことが標準的な手法でした. しかし,WWDC2014においてiOSにもdynamic frameworkが解放されました. それに伴いCocoaPodsやCarthageなどの構成管理ツールもdynamic frameworkへの対応が進められています.
さて,先ほどのbundleですが,dynamic frameworkに対応するとどうなるのでしょうか? frameworkを使うと,bundleはアプリケーションではなくそのframeworkそのものにbundleされます. つまり,frameworkを使った際はbundleからデータをロードする際,frameworkのbundleからリソースをロードするためにこのメソッドを使うことができません.
そこで,ライブラリ側でのbundleのロードについては,[NSBundle bundleForClass:]
を利用することでうまくいきます.
let bundle = NSBundle(forClass: TheLibrary.self)
ライブラリで使っているクラスからbundleを特定することでframeworkのbundleにアクセスできます.
従来の方式でもbundleもろともアプリケーションに直接埋め込んでいたのですから,当然動作します([NSBundle mainBundle]
と同じものが返ってくる).
まとめ
ローカライズや独自のリソースを使っているライブラリの多くは[NSBundle mainBundle]
を使っているでしょう.
これは完全にcontributeチャンスですので,心当たりがあればすかさずcontributeいたしましょう.
筆者も既に2つのプロダクトにcontributeしております.