Swiftでbundle内のファイル検索
今ひとつbundleがなんなのかわかっていないのだが、ちょっと実験してみたので書く。
test.bundle
|ーhoge.xml
|_text
|_hoge.txt
このbundle内のxmlファイルをパースしたいのだが、まずはどうやってアクセスしてみたらいいのかを調べてみた。
// test.bundleのパスは動的っぽい if let bundlepath = NSBundle.mainBundle().pathForResource("test", ofType: "bundle") { let manager = NSFileManager.defaultManager() if let list = manager.contentsOfDirectoryAtPath(bundlepath, error: nil) as? [String] { // 取れたパス名配列をバラして for key in list { // パスの実体が存在するか確認 var isDir : ObjCBool = false if NSFileManager.defaultManager().fileExistsAtPath(bundlepath + "/" + key, isDirectory: &isDir) { // ディレクトリかどうか確認して if isDir { println("\(key) is Directory.") } else { println("\(key) is exist.") } } else { println("\(key) is not exist.") } } } }
NSBundle.mainBundle().pathForResource
を使ってtest.bundle
のパスを取得する。
このパスには桁数の多い16進数が含まれているため、なんかこう、動的に割り当てられるものなんじゃないかと推測してみたり。
NSFileManager
クラスのcontentsOfDirectoryAtPath
メソッドを利用して、test.bundle
の中身を文字列配列list
として取得する。
上のソースの実行結果を見ればわかるが、残念ながらこのlist
は再帰的に取得されたものではないため、test.bundle
直下のファイルしか格納されていない。
その上、ファイルと書いたが、実際にはファイルとディレクトリが混在している(hoge.xml
とtext
ディレクトリ)。
このことは、その先のfileExistsAtPath
メソッドで確認している。
fileExistsAtPath
メソッドには引数の数によって、ファイルの存在を確認するだけのものと、そのパスが示すものがファイルなのかディレクトリなのかの判断もしてくれるものとの違いがある。
この手法の一番エレガントじゃないなと思うポイントは、test.bundle
のパス文字列に/
を足して、さらにtest.bundle
下の格納物のパスを足してフルパス文字列を作成している点だ。
そして、それをクリアする方法もちゃんと用意されている。
if let bundlepath = NSBundle.mainBundle().pathForResource("test", ofType: "bundle") { // test.bundleの中身を知る let manager = NSFileManager.defaultManager() // 再帰的にファイルの一覧を取得する if let paths = manager.enumeratorAtPath(bundlepath) { while let file = paths.nextObject() as? String { println(file) } } }
これを実行すると、
hoge.xml
text
text/hoge.txt
この様に出力される。
text
ディレクトリが少し邪魔な気がするが、先のfileExistsAtPath
メソッドを利用すれば、無視することも可能だろう。
/
を文字列連結することなくtest.bundle
の中身を知ることが出来た。
基本的にはネットでかき集めた情報の継ぎ接ぎなので、同じ目的のことをもっと詳しく知りたいという方は、「Swift 関数名」や「iOS 関数名」などで検索すると捗ると思われる。
以下、余談。
この先の作業に必要なので、アプリのサンドボックスについて調べてみた。
なるほどなーと思ったのだが、一点だけ。
上記では
NSSearchPathForDirectoriesInDomains(directory: NSSearchPathDirectory, domainMask: NSSearchPathDomainMask, expandTilde: Bool)
ではなく
NSFileManager.defaultManager().URLsForDirectory(directory: NSSearchPathDirectory, inDomains: NSSearchPathDomainMask)
をアップルが推奨している、と書いてある。
が、iOS8.0より前のバージョンがDeployment Targetの場合、`NSSearchPathForDirectoriesInDomains
を使用すると特に問題ないのだが、URLsForDirectory
使った場合、実行時にエラーが出た。
特にiOS8からはいろいろ変わったみたいなので、気をつけないといけない。
上記は取り消し。
あとで追記記事出す。