2
1

More than 3 years have passed since last update.

iOSアプリに必要なデータをCoreDataでbundleする

Last updated at Posted at 2020-02-27

iOSアプリで読み取り専用データをbundleするための方法

データ作成

実際に使うものと同様のデータモデルで作成する。

https://qiita.com/kenmaz/items/818d61cd0ece8664c017
の設定をしておくと、SQLiteのファイルパスがログに出力されるので便利。

サイズを小さくするためにVACUUMする。

sqlite> VACUUM;

Bundleのやり方

普通にSQLiteのファイルをドラッグアンドドロップしてbundleする。

書き込みたい場合は Application Support とかにコピーしてから使う必要があるが、読み取り専用なのでその必要はない。
ただし、sqliteの一時ファイルである Hogehoge.sqlite-wal と Hogehoge.sqlite-shm も一緒にbundleしてあげる必要がある。
これが存在しないと、Unable to open って怒られる。
両方とも空ファイルでOK。
image.png

↑のはiOS11で開けないですよってクラッシュすることが判明。
iOS13でもなんかwarnちょいちょい出てたし、やはりきちんとApplication Supportにコピーすべきっぽい。
-walと-shmは空ファイル作成すれば良いのでbundleする必要はない。

読み込み

private(set) lazy var container: NSPersistentContainer? = {
    let container = NSPersistentContainer(name: "Bundle")

    let dbBaseUrl = try! FileManager.default
        .url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
        .appendingPathComponent("Bundle")
    let dbUrl = dbBaseUrl.appendingPathExtension("sqlite")

    if !FileManager.default.fileExists(atPath: dbUrl.path) {
        do {
            for fileExtension in ["sqlite-wal", "sqlite-shm"] {
                try "".write(to: dbBaseUrl.appendingPathExtension(fileExtension), atomically: false, encoding: .utf8)
            }

            let source = Bundle.main.url(forResource: "Bundle", withExtension: "sqlite")!
            try FileManager.default.copyItem(at: source, to: dbUrl)
        } catch {
            for fileExtension in ["sqlite", "sqlite-wal", "sqlite-shm"] {
                try? FileManager.default.removeItem(at: dbBaseUrl.appendingPathExtension(fileExtension))
            }

            なんやかんやしてユーザーに失敗したことを伝える
            return nil
        }
    }

    let description = NSPersistentStoreDescription()
    description.url = dbUrl
    description.isReadOnly = true

    container.persistentStoreDescriptions = [description]

    container.loadPersistentStores(completionHandler: { (_, error) in
        if let error = error { fatalError("Unresolved error \(error)") }
    })
    return container
}()
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1