如何在Swift中将回调函数传递给sqlite3_exec
?
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>>#>)
答案 0 :(得分:2)
Swift 2.2为实现sqlite3_exec
callback
函数提供了两个选项:(1)全局,非实例func
过程或(2)非捕获文字{{1闭包。
sqlite.org的"SQLite in 5 minutes or less"示例在Swift Xcode7项目here中实现。
可读{}
typealias
回调方法
typealias sqlite3 = COpaquePointer
typealias CCharHandle = UnsafeMutablePointer<UnsafeMutablePointer<CChar>>
typealias CCharPointer = UnsafeMutablePointer<CChar>
typealias CVoidPointer = UnsafeMutablePointer<Void>
关闭方法
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
}
答案 1 :(得分:0)
这是(目前)不可能的。 Xcode 6 beta 4发行说明:
但是,您无法调用C函数指针或将闭包转换为 C函数指针类型。
作为一种解决方法,您可以将sqlite3_exec
与其回调放在一起
C包装函数并从Swift调用。
答案 2 :(得分:0)
我想为Swift 3和Linux的@l --marc l答案提供更新,这有助于我启动并运行。谢谢@l --marc l!
回调方法
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
}
关闭方法
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
}
<强>测试强>
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)")
}
}
答案 3 :(得分:0)
那个 C 函数的第一个参数(sqlite3_exec
的第三个参数)是你传递给 sqlite3_exec
的第四个参数的东西。因此,可以将 Swift 闭包传递给 sqlite3_exec
。
// Define a Type for later loading in the C function
typealias RowHandler = (
Int32,
UnsafeMutablePointer<UnsafeMutablePointer<CChar>?>?,
UnsafeMutablePointer<UnsafeMutablePointer<CChar>?>?
) -> Void
// The Swift closure to pass into sqlite3_exec
var rowHandler: RowHandler = { count, names, values in
// Do anything you want
}
let state = withUnsafeMutablePointer(to: &rowHandler) { rowHandlerPointer in
return sqlite3_exec(
connection,
"SOME SQLITE STATEMENT",
{ rowHandlerRawPointer, columnCount, values, columns in
// Load the pointer as the Type of the closure
let rowHandler = rowHandlerRawPointer!.load(as: RowHandler.self)
// Use it!
rowHandler(columnCount, columns, values)
},
rowHandlerPointer, // This will become rowHandlerRawPointer in the C function
nil
)
}
因为 RowHandler
是一个 Swift 闭包类型,我们可以将它作为包装方法的参数:
class SQLiteDatabase {
// Define a closure type for later loading in the C function
typealias RowHandler = (
Int32,
UnsafeMutablePointer<UnsafeMutablePointer<CChar>?>?,
UnsafeMutablePointer<UnsafeMutablePointer<CChar>?>?
) -> Void
var connection: OpaquePointer?
// Other methods...
func execute(_ statement: String, receiveRow: @escaping RowHandler) -> Int32 {
// The Swift closure to pass into sqlite3_exec
var rowHandler = receiveRow
let state = withUnsafeMutablePointer(to: &rowHandler) { rowHandlerPointer in
return sqlite3_exec(
connection,
statement,
{ rowHandlerRawPointer, columnCount, values, columns in
// Load the pointer as the Type of the closure
let rowHandler = rowHandlerRawPointer!.load(as: RowHandler.self)
// Use it!
rowHandler(columnCount, columns, values)
},
rowHandlerPointer, // This will become rowHandlerRawPointer in the C function
nil
)
}
return state
}
}
用法:
func result(database: SQLiteDatabase) -> [[String: String]] {
var rows = [[String: String]]()
_ = database.execute("SOME STATEMENT") { (count, names, values) in
var row = [String: String]()
for index in 0..<Int(count) {
guard let name = names?[index], let value = values?[index] else { continue }
row[String(cString: name)] = String(cString: value)
}
rows.append(row)
}
return rows
}