Reputation: 49
My application is supposed to use SQLite database, which I want to plug into the application. The sqlite file is located directly in the application folder (you can see in the screenshot). If I add the full path in the line let storeUrl = URL(fileURLWithPath:FileManager.default.currentDirectoryPath).appendingPathComponent("/Users/nm/App/Songbook/Model.sqlite")
then the application reads the data from the database. But if I type only Model.sqlite, the application does not read. I can not leave it like this in the final version of the application. Please suggest what I am doing wrong. Below is the full code.
struct PersistenceController {
static let shared = PersistenceController()
let container: NSPersistentContainer
init() {
container = NSPersistentContainer(name: "Model")
let storeUrl = URL(fileURLWithPath: FileManager.default.currentDirectoryPath).appendingPathComponent("/Users/nm/App/Spiewnik/Spiewnik/Model.sqlite")
container.persistentStoreDescriptions = [NSPersistentStoreDescription(url: storeUrl)]
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
}
UPDATA: My code now looks like this and in the simulator everything works. However, on the phone the database is empty.
static let shared = PersistenceController()
let container: NSPersistentContainer
init() {
container = NSPersistentContainer(name: "Model")
let dbName = "Model.sqlite"
let dbUrl = getDocumentsDirectory().appendingPathComponent(dbName)
if !FileManager.default.fileExists(atPath: dbUrl.path) {
//move the file
do {
if let fileURL = Bundle.main.url(forResource: "Model", withExtension: "sqlite"){
try FileManager.default.copyItem(at: fileURL, to: dbUrl)
}
} catch {
print(error)
fatalError(error.localizedDescription)
}
}
container.persistentStoreDescriptions = [NSPersistentStoreDescription(url: dbUrl)]
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
}
func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask) //or .libraryDirectory
let documentsDirectory = paths[0]
return documentsDirectory
}
Upvotes: 1
Views: 274
Reputation: 52387
It looks like you're trying to load your database from your app's bundle, which is going to be problematic because bundle files aren't writable. Instead, you need to copy it to a location you'll have read/write access to. One possibility is the application's documents directory (or library directory, which is common on macOS).
First, you'll want to be able to get the URL for that directory:
func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask) //or .libraryDirectory
let documentsDirectory = paths[0]
return documentsDirectory
}
Then, check to see if the database exists there already. If not, copy your bundle file:
let dbName = "Model.sqlite"
let dbUrl = getDocumentsDirectory().appendingPathComponent(dbName)
if !FileManager.default.fileExists(atPath: dbUrl.path) {
//move the file
do {
try FileManager.default.copyItem(at: Bundle.main.url(forResource: "Model", withExtension: "sqlite")!, to: dbUrl)
} catch {
print(error)
fatalError(error.localizedDescription)
}
}
//load your database from dbUrl here
Then, you can use dbUrl
and load your database from the file that you've now copied over.
Upvotes: 1