2014-07-16 3 views
6

Come si passa una funzione di callback a sqlite3_exec in swift?Come posso passare una funzione di callback a sqlite3_exec in swift?

sqlite_str = sqlite_str + "\(sqlite_property_str))"; 

    var str:NSString = sqlite_str; 

    var sqlite:COpaquePointer = share().sqlite3_db; 
    var errmsg:UnsafePointer<Int8> = nil 

    let rc = sqlite3_exec(sqlite, str.cStringUsingEncoding(NSUTF8StringEncoding), <#callback: CFunctionPointer<((UnsafePointer<()>, Int32, UnsafePointer<UnsafePointer<Int8>>, UnsafePointer<UnsafePointer<Int8>>) -> Int32)>#>, <#UnsafePointer<()>#>, <#errmsg: UnsafePointer<UnsafePointer<Int8>>#>) 

risposta

0

Questo è (attualmente) non possibile. Il Xcode 6 beta 4 note di rilascio Stato:

Tuttavia, non è possibile chiamare un puntatore a funzione C o convertire una chiusura a C tipo puntatore a funzione.

Come soluzione alternativa, si potrebbe mettere sqlite3_exec insieme al suo callback in una funzione wrapper C e chiamare tale da Swift.

2

Swift 2.2 fornisce due opzioni per l'implementazione della funzione sqlite3_execcallback: (1) un globale, non esempio func procedura o (2) un non-catturante letterale {} chiusura.

L'esempio "SQLite in 5 minutes or less" diè implementato in un progetto Swift Xcode7 here.

leggibile typealias

typealias sqlite3 = COpaquePointer 
typealias CCharHandle = UnsafeMutablePointer<UnsafeMutablePointer<CChar>> 
typealias CCharPointer = UnsafeMutablePointer<CChar> 
typealias CVoidPointer = UnsafeMutablePointer<Void> 

richiamata Approach

func callback(
    resultVoidPointer: CVoidPointer, // void *NotUsed 
    columnCount: CInt,    // int argc 
    values: CCharHandle,    // char **argv  
    columns: CCharHandle    // char **azColName 
    ) -> CInt { 
    for i in 0 ..< Int(columnCount) { 
     guard let value = String.fromCString(values[i]) 
     else { continue } 
     guard let column = String.fromCString(columns[i]) 
     else { continue } 
     print("\(column) = \(value)") 
    } 
    return 0 // status ok 
} 

func sqlQueryCallbackBasic(argc: Int, argv: [String]) -> Int { 
    var db: sqlite3 = nil 
    var zErrMsg:CCharPointer = nil 
    var rc: Int32 = 0 // result code 

    if argc != 3 { 
     print(String(format: "ERROR: Usage: %s DATABASE SQL-STATEMENT", argv[0])) 
     return 1 
    } 

    rc = sqlite3_open(argv[1], &db) 
    if rc != 0 { 
     print("ERROR: sqlite3_open " + String.fromCString(sqlite3_errmsg(db))! ?? "") 
     sqlite3_close(db) 
     return 1 
    } 

    rc = sqlite3_exec(db, argv[2], callback, nil, &zErrMsg) 
    if rc != SQLITE_OK { 
     print("ERROR: sqlite3_exec " + String.fromCString(zErrMsg)! ?? "") 
     sqlite3_free(zErrMsg) 
    } 

    sqlite3_close(db) 
    return 0 
} 

chiusura Approach

func sqlQueryClosureBasic(argc argc: Int, argv: [String]) -> Int { 
    var db: sqlite3 = nil 
    var zErrMsg:CCharPointer = nil 
    var rc: Int32 = 0 

    if argc != 3 { 
     print(String(format: "ERROR: Usage: %s DATABASE SQL-STATEMENT", argv[0])) 
     return 1 
    } 

    rc = sqlite3_open(argv[1], &db) 
    if rc != 0 { 
     print("ERROR: sqlite3_open " + String.fromCString(sqlite3_errmsg(db))! ?? "") 
     sqlite3_close(db) 
     return 1 
    } 

    rc = sqlite3_exec(
     db,  // database 
     argv[2], // statement 
     {  // callback: non-capturing closure 
      resultVoidPointer, columnCount, values, columns in 

      for i in 0 ..< Int(columnCount) { 
       guard let value = String.fromCString(values[i]) 
       else { continue } 
       guard let column = String.fromCString(columns[i]) 
       else { continue } 
       print("\(column) = \(value)") 
      } 
      return 0 
     }, 
     nil, 
     &zErrMsg 
    ) 

    if rc != SQLITE_OK { 
     let errorMsg = String.fromCString(zErrMsg)! ?? "" 
     print("ERROR: sqlite3_exec \(errorMsg)") 
     sqlite3_free(zErrMsg) 
    } 
    sqlite3_close(db) 
    return 0 
} 
0

Volevo fornire un aggiornamento alla risposta @l --marc l per Swift 3 e Linux che mi ha aiutato a mettermi in moto. Grazie @l --marc l!

richiamata approccio

func callback(
    resultVoidPointer: UnsafeMutablePointer<Void>?, // void *NotUsed 
    columnCount: Int32, // int argc 
    values:UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>?, // char **argv  
    columns:UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>? // char **azColName 
    ) -> CInt { 
    var dic: [String:String] = [:] 
    for i in 0 ..< Int(columnCount) { 
     guard let value = values?[i] 
     else { continue } 
     guard let column = columns?[i] 
     else { continue } 

     let strCol = String(cString:column) 
     let strVal = String(cString:value) 

     dic[strCol] = strVal 
     //print("\(strCol) = \(strVal)") 
    } 
    resultSet.append(dic) 
    return 0 // status ok 
} 

func sqlQueryCallbackBasic(dbStr:String, query:String) -> Int { 
    var db: OpaquePointer? 
    var zErrMsg:UnsafeMutablePointer<Int8>? 
    var rc: Int32 = 0 // result code 

    rc = sqlite3_open(dbStr, &db) 
    if rc != 0 { 
     print("ERROR: sqlite3_open " + String(sqlite3_errmsg(db)) ?? "") 
     sqlite3_close(db) 
     return 1 
    } 

    rc = sqlite3_exec(db, query, callback, nil, &zErrMsg) 
    if rc != SQLITE_OK { 
     let errorMsg = zErrMsg 
     print("ERROR: sqlite3_exec \(errorMsg)") 
     sqlite3_free(zErrMsg) 
    } 

    sqlite3_close(db) 
    return 0 
} 

Chiusura approccio

func sqlQueryClosureBasic(dbStr:String, query:String) -> Int { 
    var db: OpaquePointer? 
    var zErrMsg:UnsafeMutablePointer<Int8>? 
    var rc: Int32 = 0 

    rc = sqlite3_open(dbStr, &db) 
    if rc != 0 { 
     print("ERROR: sqlite3_open " + String(sqlite3_errmsg(db)) ?? "") 
     sqlite3_close(db) 
     return 1 
    } 

    rc = sqlite3_exec(
     db,  // database 
     query, // statement 
     {  // callback: non-capturing closure 
      resultVoidPointer, columnCount, values, columns in 
      var dic: [String:String] = [:] 
      for i in 0 ..< Int(columnCount) { 
       guard let value = values?[i] 
       else { continue } 
       guard let column = columns?[i] 
       else { continue } 

       let strCol = String(cString:column) 
       let strVal = String(cString:value) 

       dic[strCol] = strVal 

       //print("\(strCol) = \(strVal)") 
      } 
      resultSet.append(dic) 
      return 0 
     }, 
     nil, 
     &zErrMsg 
    ) 

    if rc != SQLITE_OK { 
     let errorMsg = zErrMsg 
     print("ERROR: sqlite3_exec \(errorMsg)") 
     sqlite3_free(zErrMsg) 
    } 
    sqlite3_close(db) 
    return 0 
} 

prova

import Glibc 

var resultSet: [[String: String]] = [[:]] 

//sqlQueryClosureBasic(dbStr:"Sqlite_Test.db", query:"SELECT * FROM Employee") 

sqlQueryCallbackBasic(dbStr:"Sqlite_Test.db", query:"SELECT * FROM Employee") 


for row in resultSet { 
    for (col, val) in row { 
     print("\(col): \(val)") 
    } 
}