3

I need to initialize a variable to connect to an SQLite database in Swift. I am using the SQLite.swift library and need to connect to the database with this line:

let db = try Connection("path/to/db.sqlite3")

However, this line by itself will not work because it needs to be surrounded with a try/catch block. Try/catch blocks will not work unless they are defined within methods or functions, so now we have

public func connectToDB() {
    do {
        let path = NSSearchPathForDirectoriesInDomains(
            .DocumentDirectory, .UserDomainMask, true
            ).first!
        let db = try Connection("\(path)/db.sqlite3")
    }
    catch {
        print("error connecting to database")
    }
}

However, this doesn't allow me to access the variable from other methods in the same file, which is what I need to do. Global let declarations also require initialization, so that means it cannot be set globally. How can I access this object from other methods within the class?

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
Chandler Freeman
  • 899
  • 1
  • 10
  • 25
  • Read [this](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html) Especially the parts about `scope` – R Menke Nov 30 '15 at 15:24
  • Alternatively to this; create a database manager object and pass a reference to that around your application. You'll find it's a lot easier when it comes to testing your application. – Abizern Nov 30 '15 at 15:28
  • Ok, I'll do this. Thank you! – Chandler Freeman Nov 30 '15 at 15:33

3 Answers3

6

You could do this:

let db = try! Connection("path/to/db.sqlite3")
// db is a Connection but the app dies if there was an error.

Or you could do this:

let db = try? Connection("path/to/db.sqlite3")
// db is an Optional<Connection> and nil if there was an error.

Or you could do this:

let db = { () -> Connection in
    do {
        return try Connection("path/to/db.sqlite3")
    } catch {
        do {
            return try Connection() // transient in-memory database
        } catch {
            fatalError()
        }
    }
}() // invoke this closure immediately

You can do whatever you like in the closure to handle an error case.

rob mayoff
  • 375,296
  • 67
  • 796
  • 848
2

I'm not sure why the answer above is correct - it seems from the original question that he was having 2 issues, 1 was using the Try/Catch, and the other was SCOPE OF VARIABLE.

If you're initializing a variable inside of a function, my understanding is that it dies with the function. I'm doing it in my code as follows:

var db: FMDatabase?

func openDB() -> FMDatabase {
    do {
        let path = NSSearchPathForDirectoriesInDomains(
            .DocumentDirectory, .UserDomainMask, true
            ).first!
        let db = try Connection("\(path)/db.sqlite3")
        return db
    }
    catch {
        print("error connecting to database")
        return nil
    }

}

Now you will have access to "db" as a class variable. Hope that helps.

user1082348
  • 229
  • 2
  • 10
0

If using the wrapper SQLite.swift the code could look like this:

var db: Connection?

func openDB() -> Connection {
    //Simply return if the connection already exists
    if db == nil {
        do { let path = NSSearchPathForDirectoriesInDomains(
            .documentDirectory, .userDomainMask, true
            ).first!
            db = try Connection("\(path)/database.sqlite3")
            print("Database opened")
            print(path)
        }
        catch {
            print("error connecting to database \(error)")
            print("In func openDB() -> Connection")
        }
    }
    return db!
}
barbsan
  • 3,418
  • 11
  • 21
  • 28
Byron
  • 31
  • 1
  • 4