Вы не можете изменять содержимое пакета. Таким образом, вы захотите скопировать файл в какой-то каталог, где его можно изменить. Исторически мы могли бы посоветовать использовать для этого папку «документы». Но в настоящее время мы используем «каталог поддержки приложений». См. Рекомендации по хранению iOS .
Во всяком случае, основная идея:
включить исходную базу данных в комплект (добавив ее к цели вашего приложения, если вы этого еще не сделали);
![enter image description here](https://i.stack.imgur.com/zDdla.png)
попробуйте открыть базу данных (с опцией 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)
}