Documents にデータを保存する意味

アプリには三つのコンテナがあり、それぞれBundle ContainerData ContaineriCloud Containerと呼ばれています。

この中で iTunes でバックアップできるのはData Containerになり、Data Containerには「Documents」「Library」「Temp」の三つのディレクトリが存在しています。どこのフォルダに何を保存するかはガイドラインで決まっているので、それに従う必要があります。

Documents

Documents について

ユーザーが生成したデータを保存するために使います。ファイル共有の機能により、ユーザーはこのディレクトリ以下にアクセスできます。したがって、ユーザーに見せても構わないファイルのみ置いてください。 iTunes および iCloud はこのディレクトリの内容をバックアップします。

Library

Library について

これは、ユーザーのデータファイル以外のファイル用の最上位ディレクトリです。通常、標準的なサブディレクトリを用意し、いずれか適当な場所に保存します。iOS アプリケーションは通常、Application Support および Caches というサブディレクトリを使いますが、独自のサブディレクトリを作成しても構いません。

ユーザーに見せたくないファイルは Library サブディレクトリ以下に置いてください。ユーザーデータのファイル保存用に使ってはなりません。

Library ディレクトリの内容は iTunes および iCloud によってバックアップされます(ただし、Caches サブディレクトリは除く)

Temp

Temp について

このディレクトリは、アプリケーションを次に起動するまで保持する必要のない一時ファイルを書き込むために使用します。不要になったファイルは削除しなければなりません。もっとも、アプリケーションが動作していないときに、システムがこのディレクトリ以下をすべて消去することがあります。 iTunes または iCloud はこのディレクトリの内容をバックアップしません。

Documents ディレクトリ

Documents ディレクトリにアクセスしようとしたら、まずパスがわからないといけません。

パスはStringURLで取得することが多いと思うのですが、結論から言えばURLで取得したほうが絶対に楽です。特に制限がなければURLで取得するようにしましょう。

private var documentDirectoryFileURL: URL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
private var documentDirectoryFilePath: String = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
1
2

URL の場合と String の場合で微妙に取得方法が違うのが面白いですね。これで非オプショナルなパスを取得することができます。

サブディレクトリ

とはいえ、Documents 直下にファイルをガンガン保存することも少ないと思います。サブディレクトリを作成し、その中にファイルを保存したいという方が多いのではないでしょうか。

let path = documentDirectoryFileURL.appendingPathComponent("JSON", isDirectory: true)
do {
    try FileManager.default.createDirectory(at: path, withIntermediateDirectories: true, attributes: nil)
} catch(let error) {
    print(error)
}
1
2
3
4
5
6

というわけで、今回は Documents 下に JSON というフォルダを作成します。作成できなかった場合はとりあえずエラーを表示していますが、ここは各自ななんか適当な処理を入れてください。withIntermediateDirectoriesというオプションにtrueを入れておけば中間ディレクトリも自動で作成してくれるので便利です。

データ書き込み

画像の場合は以下のように Data 型に変換して保存します。

// 画像書き込み
let uiimage: UIImage = UIImage() // なんか適当なUIImageを取得
let image: Data = uiimage.jpegData(compressionQuality: 0.7)! // Data型に変換
let filePath: URL = documentDirectoryFileURL.appendingPathComponent("JSON/default.jpeg")
do {
    try image.write(to: filePath)
} catch(let error) {
    print(error)
}
1
2
3
4
5
6
7
8
9

今回は JPEG で保存していますが、PNG で保存したい場合はlet image: Data = uiimage.pngData()!とすれば良いです。

テキストの場合はStringであれば標準の書き込みライブラリであるwriteが利用できます。

// テキスト書き込み
let text: String = "Hello, world!"
let filePath: URL = documentDirectoryFileURL.appendingPathComponent("JSON/default.txt")
do {
    try text.write(to: filePath, atomically: true, encoding: .utf8)
} catch(let error) {
    print(error)
}
1
2
3
4
5
6
7
8

atomicallyオプションは一時フォルダに書き込みを行い、成功すれば指定されたディレクトリにコピーするための保険のようなものです。エンコーディングは特に制限がなければ.utf8を利用するのがいいでしょう。

// JSON書き込み
let json: JSON = JSON()
let jsonString: String = json.description.data(using: String.Encoding.utf8)!
let filePath: URL = documentDirectoryFileURL.appendingPathComponent("JSON/default.json")
do {
    try jsonString.write(to: filePath, atomically: true, encoding: .utf8)
} catch(let error) {
    print(error)
}
1
2
3
4
5
6
7
8
9

JSON は結局テキストファイルなのでテキストと同じ書き込み方法が使えます。SwiftyJSON (opens new window)であれば上のコードで JSON を String に変換できるのでそれが一番手っ取り早いです。