6

I'm trying to send a request to FMDB via a Swift class.

This is working:

self.database.executeQuery("SELECT * FROM foods WHERE id = ?", withArgumentsInArray:[anID])

because I used the method executeQuery(sql, withArgumentsInArray)

But I don't know how to use the classical method with the undefined number of arguments, instead of the one with an array:

self.database.executeUpdate(<#sql: String?#>, withVAList: <#CVaListPointer#>)

I don't know how to write my arguments in withVAList.

alex.bour
  • 2,842
  • 9
  • 40
  • 66

3 Answers3

5

My solution was to create an FMDatabase wrapper:

let success:Bool = FMDatabaseWrapper().executeUpdate(sql, food.ID?, food.name?)

func executeUpdate(sql:String, _ arguments: AnyObject?...) -> Bool
  {
    return database.executeUpdate(sql, withArgumentsInArray:arguments as NSArray)
  }

It works.

alex.bour
  • 2,842
  • 9
  • 40
  • 66
  • +1 And you can just add this method as an `extension` to `FMDatabase`, and it's seamless. You might want to not make that `AnyObject` optional, though. – Rob Aug 06 '14 at 17:01
  • And, needless to say, one can do the equivalent method for `executeQuery`, e.g.: `func executeQuery(sql:String, _ arguments: AnyObject...) -> FMResultSet? { return executeQuery(sql, withArgumentsInArray: arguments as NSArray); }` (sorry for the ugly formatting). – Rob Aug 06 '14 at 17:12
2

The problem is that Swift cannot overload a same-named function with a function that takes a variable number of arguments. Thus, given a "choice" between understanding your call to executeUpdate as a call to executeUpdate:withArgumentsInArray: and a call to executeUpdate:(NSString*)..., the latter never comes up as a possibility.

However, there's really no problem, because you never actually need to call that method. It doesn't do anything except call executeUpdate:withVAList:, which you can call directly yourself, easily, by using the built-in Swift getVaList function (see https://stackoverflow.com/a/24196063/341994).

Or even better, just go right on using executeUpdate:withArgumentsInArray:. If there are no arguments, simply pass nil for the second parameter.

Community
  • 1
  • 1
matt
  • 515,959
  • 87
  • 875
  • 1,141
0

If it helps, I've created an elegant SQLite library written completely in Swift called SwiftData.

Some of its feature are:

  • Bind objects conveniently to a string of SQL
  • Support for transactions and savepoints
  • Inline error handling
  • Completely thread safe by default

It provides an easy way to execute 'changes' (e.g. INSERT, UPDATE, DELETE, etc.):

if let err = SD.executeChange("INSERT INTO Cities (Name, Population, IsWarm, FoundedIn) VALUES ('Toronto', 2615060, 0, '1793-08-27')") {
    //there was an error during the insert, handle it here
} else {
    //no error, the row was inserted successfully
}

and 'queries' (e.g. SELECT):

let (resultSet, err) = SD.executeQuery("SELECT * FROM Cities")
if err != nil {
    //there was an error during the query, handle it here
} else {
    for row in resultSet {
        if let name = row["Name"].asString() {
            println("The City name is: \(name)")
        }
        if let population = row["Population"].asInt() {
            println("The population is: \(population)")
        }
        if let isWarm = row["IsWarm"].asBool() {
            if isWarm {
                println("The city is warm")
            } else {
                println("The city is cold")
            }
        }
        if let foundedIn = row["FoundedIn"].asDate() {
            println("The city was founded in: \(foundedIn)")
        }
    }
}

Along with many more features!

You can check it out here

ryanfowler
  • 77
  • 1
  • 2