Search code examples
iosswiftsqlitefmdb

Copy Database after starting swift


this is my first DB Project, so i am facing some issues. Hopefully you can help me! I am using FMDB to have access to an existing DB. When i try to execute a simpel Query like "Select * From films" it returns stuff like "no such table". I looked into the folder of the IPhone Simulator and found the DB, but it was empty. My next Step was, to include this Method:

func copyDatabaseIfNeeded() {
    // Move database file from bundle to documents folder

    let fileManager = FileManager.default

    let documentsUrl = fileManager.urls(for: .documentDirectory,
                                        in: .userDomainMask)

    guard documentsUrl.count != 0 else {
        return // Could not find documents URL
    }

    let finalDatabaseURL = documentsUrl.first!.appendingPathComponent("foo.db")

    if !( (try? finalDatabaseURL.checkResourceIsReachable()) ?? false) {
        print("DB does not exist in documents folder")

        let documentsURL = Bundle.main.resourceURL?.appendingPathComponent("foo.db")

        do {
            try fileManager.copyItem(atPath: (documentsURL?.path)!, toPath: finalDatabaseURL.path)
        } catch let error as NSError {
            print("Couldn't copy file to final location! Error:\(error.description)")
        }

    } else {
        print("Database file found at path: \(finalDatabaseURL.path)")
    }
}

But this Method is not working. Im calling it from DidFinishLaunching.

This is the error message:

OverBurned/Library/Developer/CoreSimulator/Devices/B5EAE004-A036-4BD5-A692-C25EF3875D25/data/Containers/Bundle/Application/5ABA8D38-7625-4F98-83E9-4266A3E5B6B0/GameOne.app/foo.db, NSUnderlyingError=0x600000053230 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}

()

Am i using the wrong Method or is implemented wrong?


Solution

  • The error is clear. There is no foo.db in your app's resource bundle.

    You do have lots of issues with the code you posted.

    1. Your code to get the path to foo.db is far from ideal.
    2. You do not properly deal with optionals.
    3. Your variable names need to be improved. Example - the 2nd documentsURL implies it is a URL referencing the "Documents" folder. It is actually a URL to a file in the resource bundle.
    4. There is no need for NSError.

    Here is how I would write this code:

    func copyDatabaseIfNeeded() {
        // Move database file from bundle to documents folder
    
        let fileManager = FileManager.default
    
        guard let documentsUrl = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
    
        let finalDatabaseURL = documentsUrl.appendingPathComponent("foo.db")
    
        do {
            if !fileManager.fileExists(atPath: finalDatabaseURL.path) {
                print("DB does not exist in documents folder")
    
                if let dbFilePath = Bundle.main.path(forResource: "foo", ofType: "db") {
                    try fileManager.copyItem(atPath: dbFilePath, toPath: finalDatabaseURL.path)
                } else {
                    print("Uh oh - foo.db is not in the app bundle")
                }
            } else {
                print("Database file found at path: \(finalDatabaseURL.path)")
            }
        } catch {
            print("Unable to copy foo.db: \(error)")
        }
    }