Сохранение изменений базы данных в файл .db с помощью SQLite (Swift) - PullRequest
1 голос
/ 02 июня 2019

В моем проекте я открываю уже существующую базу данных из .db с sqlite3_open. Этот файл был создан с помощью инструмента командной строки sqlite3. Я обновляю некоторые строки в таблице, которая работает нормально, но эти обновления производятся только во временном экземпляре базы данных. Как мне также обновить файл .db для будущих запусков моего проекта для работы с обновленными данными?

Кто-то спросил здесь , как сохранить базу данных SQLite в Swift. Но ответ кажется мне как-то неудовлетворительным, потому что файл должен быть записан в том же формате, что и созданный sqlite3, чтобы его можно было снова открыть через sqlite3_open.

Может быть, есть даже функция, представленная SQLite? Я ничего не мог найти для этого ...

1 Ответ

1 голос
/ 03 июня 2019

Вы не можете изменять содержимое пакета. Таким образом, вы захотите скопировать файл в какой-то каталог, где его можно изменить. Исторически мы могли бы посоветовать использовать для этого папку «документы». Но в настоящее время мы используем «каталог поддержки приложений». См. Рекомендации по хранению iOS .

Во всяком случае, основная идея:

  • включить исходную базу данных в комплект (добавив ее к цели вашего приложения, если вы этого еще не сделали);

    enter image description here

  • попробуйте открыть базу данных (с опцией SQLITE_READWRITE, но не с опцией SQLITE_CREATE ... мы не хотим, чтобы она создала пустую базу данных, если она не нашла) в каталоге поддержки приложения ; и

  • в случае сбоя (поскольку файл не найден) скопируйте базу данных из комплекта в каталог поддержки приложений и повторите попытку

Таким образом, возможно что-то вроде:

var db: OpaquePointer?

enum DatabaseError: Error {
    case bundleDatabaseNotFound
    case sqliteError(Int32, String?)
}

func openDatabase() throws {
    let fileURL = try FileManager.default.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
        .appendingPathComponent("database.db")

    // try opening database and just return if it succeeded

    if sqlite3_open_v2(fileURL.path, &db, SQLITE_OPEN_READWRITE, nil) == SQLITE_OK {
        return
    }

    // if it failed, clean up before trying again ...

    sqlite3_close(db)
    db = nil

    // then copy database from bundle ...

    guard let bundlePath = Bundle.main.url(forResource: "database", withExtension: "db") else {
        throw DatabaseError.bundleDatabaseNotFound
    }
    try FileManager.default.copyItem(at: bundlePath, to: fileURL)

    // and try again

    let rc = sqlite3_open_v2(fileURL.path, &db, SQLITE_OPEN_READWRITE, nil)

    if rc == SQLITE_OK { return }

    // and if it still failed, again, clean up, and then throw error

    let errorMessage = sqlite3_errmsg(db)
        .flatMap { String(cString: $0) }

    sqlite3_close(db)
    db = nil

    throw DatabaseError.sqliteError(rc, errorMessage)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...