oculorum
oculorum

Reputation: 49

Attaching SQLite database to an application

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)")
            }
        })
    }

enter image description here

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

Answers (1)

jnpdx
jnpdx

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

Related Questions