FMDatabase + swift + request with undefined number of arguments
Asked Answered
E

3

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.

Expel answered 12/6, 2014 at 13:29 Comment(1)
I think that Obj-C methods with a variable argument list are not converted properly (yet).Fm
E
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.

Expel answered 12/6, 2014 at 15:11 Comment(2)
+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.Hydrostat
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).Hydrostat
S
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://mcmap.net/q/388284/-how-do-you-call-an-objective-c-variadic-method-from-swift).

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

Sedimentary answered 30/8, 2014 at 16:33 Comment(0)
S
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

Salzman answered 26/8, 2014 at 5:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.