在 Swift 中访问 SQLite 数据库

我正在寻找一种方法来访问一个 SQLite 数据库在我的应用程序与 Swift 代码。

我知道我可以在 Objective C 中使用 SQLite Wrapper 并使用桥接头,但是我更愿意完全在 Swift 中完成这个项目。有没有一种方法可以做到这一点,如果有的话,有没有人可以指给我一个参考,说明如何提交查询,检索行,等?

142783 次浏览

您所能做的最好的事情就是在桥接头中导入动态库:

  1. 将 libsqlite3.dylib 添加到“ Link Binary With Library”构建阶段
  2. 创建一个“ Bridge-Header.h”并将 #import <sqlite3.h>添加到顶部
  3. 在「快速编译器程式码生成」的建置设定中,将「 Objective-C 桥接头」设定为「桥接头」

You will then be able to access all of the c methods like sqlite3_open from your swift code.

但是,您可能只想使用 FMDB并通过桥接头导入它,因为它是一个更面向对象的 sqlite 包装器。在 Swift 中处理 C 指针和结构会很麻烦。

我也在寻找与 SQLite 交互的方法,就像我以前在 Objective-C 中所做的那样。不可否认,由于 C 兼容性,我只使用了直接的 C API。

由于目前 Swift 中没有针对 SQLite 的包装器,而且上面提到的 SQLiteDB 代码的级别更高一些,并且假定有一定的用法,因此我决定创建一个包装器,并在这个过程中对 Swift 有所了解。你可以在这里找到它: https://github.com/chrismsimpson/SwiftSQLite

var db = SQLiteDatabase();
db.open("/path/to/database.sqlite");


var statement = SQLiteStatement(database: db);


if ( statement.prepare("SELECT * FROM tableName WHERE Id = ?") != .Ok )
{
/* handle error */
}


statement.bindInt(1, value: 123);


if ( statement.step() == .Row )
{
/* do something with statement */
var id:Int = statement.getIntAt(0)
var stringValue:String? = statement.getStringAt(1)
var boolValue:Bool = statement.getBoolAt(2)
var dateValue:NSDate? = statement.getDateAt(3)
}


statement.finalizeStatement(); /* not called finalize() due to destructor/language keyword */

我已经创建了一个完全用 Swift 编写的优雅的 SQLite 库,称为 SwiftData

它的一些特点是:

  • 方便地将对象绑定到 SQL 字符串
  • 支持事务和保存点
  • 内联错误处理
  • 默认情况下完全线程安全

它提供了一种简单的方法来执行“更改”(例如 INSERT、 UPDATE、 DELETE 等) :

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!

你可以看看 给你

我写了 用 Swift 编写的 SQLite3包装器库

这实际上是一个具有非常简单 API 的非常高级的包装器,但无论如何,它具有低级的 C interop 代码,我在这里展示了其中(简化的)一部分,以显示 C interop。

    struct C
{
static let  NULL        =   COpaquePointer.null()
}


func open(filename:String, flags:OpenFlag)
{
let name2   =   filename.cStringUsingEncoding(NSUTF8StringEncoding)!
let r       =   sqlite3_open_v2(name2, &_rawptr, flags.value, UnsafePointer<Int8>.null())
checkNoErrorWith(resultCode: r)
}


func close()
{
let r   =   sqlite3_close(_rawptr)
checkNoErrorWith(resultCode: r)
_rawptr =   C.NULL
}


func prepare(SQL:String) -> (statements:[Core.Statement], tail:String)
{
func once(zSql:UnsafePointer<Int8>, len:Int32, inout zTail:UnsafePointer<Int8>) -> Core.Statement?
{
var pStmt   =   C.NULL
let r       =   sqlite3_prepare_v2(_rawptr, zSql, len, &pStmt, &zTail)
checkNoErrorWith(resultCode: r)


if pStmt == C.NULL
{
return  nil
}
return  Core.Statement(database: self, pointerToRawCStatementObject: pStmt)
}


var stmts:[Core.Statement]  =   []
let sql2    =   SQL as NSString
var zSql    =   UnsafePointer<Int8>(sql2.UTF8String)
var zTail   =   UnsafePointer<Int8>.null()
var len1    =   sql2.lengthOfBytesUsingEncoding(NSUTF8StringEncoding);
var maxlen2 =   Int32(len1)+1


while let one = once(zSql, maxlen2, &zTail)
{
stmts.append(one)
zSql    =   zTail
}


let rest1   =   String.fromCString(zTail)
let rest2   =   rest1 == nil ? "" : rest1!


return  (stmts, rest2)
}


func step() -> Bool
{
let rc1 =   sqlite3_step(_rawptr)


switch rc1
{
case SQLITE_ROW:
return  true


case SQLITE_DONE:
return  false


default:
database.checkNoErrorWith(resultCode: rc1)
}
}


func columnText(at index:Int32) -> String
{
let bc  =   sqlite3_column_bytes(_rawptr, Int32(index))
let cs  =   sqlite3_column_text(_rawptr, Int32(index))


let s1  =   bc == 0 ? "" : String.fromCString(UnsafePointer<CChar>(cs))!
return  s1
}


func finalize()
{
let r   =   sqlite3_finalize(_rawptr)
database.checkNoErrorWith(resultCode: r)


_rawptr =   C.NULL
}

如果希望获得此低级包装器的完整源代码,请参见这些文件。

虽然您可能应该使用许多 SQLite 包装器之一,但是如果您想知道如何自己调用 SQLite 库,您可以:

  1. Configure your Swift project to handle SQLite C calls. If using Xcode 9 or later, you can simply do:

    import SQLite3
    
  2. Create/open database.

    let fileURL = try! FileManager.default
    .url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
    .appendingPathComponent("test.sqlite")
    
    
    // open database
    
    
    var db: OpaquePointer?
    guard sqlite3_open(fileURL.path, &db) == SQLITE_OK else {
    print("error opening database")
    sqlite3_close(db)
    db = nil
    return
    }
    

    注意,我知道在打开失败时关闭数据库看起来很奇怪,但是 sqlite3_open 文件明确指出我们必须这样做以避免内存泄漏:

    无论打开时是否发生错误,与 数据库连接句柄相关联的资源都应该在不再需要时通过将其传递给 sqlite3_close()来释放。

  3. 使用 sqlite3_exec执行 SQL (例如 create table)。

    if sqlite3_exec(db, "create table if not exists test (id integer primary key autoincrement, name text)", nil, nil, nil) != SQLITE_OK {
    let errmsg = String(cString: sqlite3_errmsg(db)!)
    print("error creating table: \(errmsg)")
    }
    
  4. Use sqlite3_prepare_v2 to prepare SQL with ? placeholder to which we'll bind value.

    var statement: OpaquePointer?
    
    
    if sqlite3_prepare_v2(db, "insert into test (name) values (?)", -1, &statement, nil) != SQLITE_OK {
    let errmsg = String(cString: sqlite3_errmsg(db)!)
    print("error preparing insert: \(errmsg)")
    }
    
    
    if sqlite3_bind_text(statement, 1, "foo", -1, SQLITE_TRANSIENT) != SQLITE_OK {
    let errmsg = String(cString: sqlite3_errmsg(db)!)
    print("failure binding foo: \(errmsg)")
    }
    
    
    if sqlite3_step(statement) != SQLITE_DONE {
    let errmsg = String(cString: sqlite3_errmsg(db)!)
    print("failure inserting foo: \(errmsg)")
    }
    

    注意,它使用 SQLITE_TRANSIENT常量 可以实施,如下所示:

    internal let SQLITE_STATIC = unsafeBitCast(0, to: sqlite3_destructor_type.self)
    internal let SQLITE_TRANSIENT = unsafeBitCast(-1, to: sqlite3_destructor_type.self)
    
  5. Reset SQL to insert another value. In this example, I'll insert a NULL value:

    if sqlite3_reset(statement) != SQLITE_OK {
    let errmsg = String(cString: sqlite3_errmsg(db)!)
    print("error resetting prepared statement: \(errmsg)")
    }
    
    
    if sqlite3_bind_null(statement, 1) != SQLITE_OK {
    let errmsg = String(cString: sqlite3_errmsg(db)!)
    print("failure binding null: \(errmsg)")
    }
    
    
    if sqlite3_step(statement) != SQLITE_DONE {
    let errmsg = String(cString: sqlite3_errmsg(db)!)
    print("failure inserting null: \(errmsg)")
    }
    
  6. Finalize prepared statement to recover memory associated with that prepared statement:

    if sqlite3_finalize(statement) != SQLITE_OK {
    let errmsg = String(cString: sqlite3_errmsg(db)!)
    print("error finalizing prepared statement: \(errmsg)")
    }
    
    
    statement = nil
    
  7. Prepare new statement for selecting values from table and loop through retrieving the values:

    if sqlite3_prepare_v2(db, "select id, name from test", -1, &statement, nil) != SQLITE_OK {
    let errmsg = String(cString: sqlite3_errmsg(db)!)
    print("error preparing select: \(errmsg)")
    }
    
    
    while sqlite3_step(statement) == SQLITE_ROW {
    let id = sqlite3_column_int64(statement, 0)
    print("id = \(id); ", terminator: "")
    
    
    if let cString = sqlite3_column_text(statement, 1) {
    let name = String(cString: cString)
    print("name = \(name)")
    } else {
    print("name not found")
    }
    }
    
    
    if sqlite3_finalize(statement) != SQLITE_OK {
    let errmsg = String(cString: sqlite3_errmsg(db)!)
    print("error finalizing prepared statement: \(errmsg)")
    }
    
    
    statement = nil
    
  8. Close database:

    if sqlite3_close(db) != SQLITE_OK {
    print("error closing database")
    }
    
    
    db = nil
    

For Swift 2 and older versions of Xcode, see previous revisions of this answer.

将 Swift 项目配置为处理 SQLite C 调用:

创建到项目的桥接头文件。参见将 Objective-C 导入 Swift 和 Cocoa 以及 Objective-C 的使用部分。这个桥接头应该导入 sqlite3.h:

将 libsqlite3.0. dylib 添加到您的项目中。

并使用以下代码

    func executeQuery(query: NSString ) -> Int
{
if  sqlite3_open(databasePath! as String, &database) != SQLITE_OK
{
println("Databse is not open")
return 0
}
else
{
query.stringByReplacingOccurrencesOfString("null", withString: "")
var cStatement:COpaquePointer = nil
var executeSql = query as NSString
var lastId : Int?
var sqlStatement = executeSql.cStringUsingEncoding(NSUTF8StringEncoding)
sqlite3_prepare_v2(database, sqlStatement, -1, &cStatement, nil)
var execute = sqlite3_step(cStatement)
println("\(execute)")
if execute == SQLITE_DONE
{
lastId = Int(sqlite3_last_insert_rowid(database))
}
else
{
println("Error in Run Statement :- \(sqlite3_errmsg16(database))")
}
sqlite3_finalize(cStatement)
return lastId!
}
}
func ViewAllData(query: NSString, error: NSError) -> NSArray
{
var cStatement = COpaquePointer()
var result : AnyObject = NSNull()
var thisArray : NSMutableArray = NSMutableArray(capacity: 4)
cStatement = prepare(query)
if cStatement != nil
{
while sqlite3_step(cStatement) == SQLITE_ROW
{
result = NSNull()
var thisDict : NSMutableDictionary = NSMutableDictionary(capacity: 4)
for var i = 0 ; i < Int(sqlite3_column_count(cStatement)) ; i++
{
if sqlite3_column_type(cStatement, Int32(i)) == 0
{
continue
}
if sqlite3_column_decltype(cStatement, Int32(i)) != nil && strcasecmp(sqlite3_column_decltype(cStatement, Int32(i)), "Boolean") == 0
{
var temp = sqlite3_column_int(cStatement, Int32(i))
if temp == 0
{
result = NSNumber(bool : false)
}
else
{
result = NSNumber(bool : true)
}
}
else if sqlite3_column_type(cStatement,Int32(i)) == SQLITE_INTEGER
{
var temp = sqlite3_column_int(cStatement,Int32(i))
result = NSNumber(int : temp)
}
else if sqlite3_column_type(cStatement,Int32(i)) == SQLITE_FLOAT
{
var temp = sqlite3_column_double(cStatement,Int32(i))
result = NSNumber(double: temp)
}
else
{
if sqlite3_column_text(cStatement, Int32(i)) != nil
{
var temp = sqlite3_column_text(cStatement,Int32(i))
result = String.fromCString(UnsafePointer<CChar>(temp))!
                            

var keyString = sqlite3_column_name(cStatement,Int32(i))
thisDict.setObject(result, forKey: String.fromCString(UnsafePointer<CChar>(keyString))!)
}
result = NSNull()


}
if result as! NSObject != NSNull()
{
var keyString = sqlite3_column_name(cStatement,Int32(i))
thisDict.setObject(result, forKey: String.fromCString(UnsafePointer<CChar>(keyString))!)
}
}
thisArray.addObject(NSMutableDictionary(dictionary: thisDict))
}
sqlite3_finalize(cStatement)
}
return thisArray
}
func prepare(sql : NSString) -> COpaquePointer
{
var cStatement:COpaquePointer = nil
sqlite3_open(databasePath! as String, &database)
var utfSql = sql.UTF8String
if sqlite3_prepare(database, utfSql, -1, &cStatement, nil) == 0
{
sqlite3_close(database)
return cStatement
}
else
{
sqlite3_close(database)
return nil
}
}
}

Swift 2和 Swift 3的另一个 SQLite 包装器: http://github.com/groue/GRDB.swift

特点:

  • 一个对 Ccgus/fmdb用户来说很熟悉的 API

  • 利用 Swift 标准库的低级 SQLite API

  • 对 SQL 敏感的开发人员来说,这是一个漂亮的 Swift 查询界面

  • Support for the SQLite WAL mode, and concurrent database access for extra performance

  • 一个 Record 类,它包装结果集,将自定义 SQL 查询作为早餐,并提供基本的 CRUD 操作

  • 快速类型自由: 选择适合您的数据的正确的快速类型。需要时使用 Int64,或者坚持使用方便的 Int。存储和读取 NSDate 或 NSDateComponent。为离散数据类型声明 Swift 枚举。定义自己的数据库可转换类型。

  • 数据库迁移

  • 速度: https://github.com/groue/GRDB.swift/wiki/Performance

有时,Sqlite.org上显示的 “ SQLite 在5分钟内完成”方法的 Swift 版本就足够了。 “5分钟或更少”的方法使用 sqlite3_exec(),它是 sqlite3_prepare()sqlite3_step()sqlite3_column()sqlite3_finalize()的便捷包装器。

Swift 2.2 can directly support the sqlite3_exec() callback function pointer as either a global, non-instance procedure func or a non-capturing literal closure {}.

可读 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
}

结束方法

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
}

为了准备一个 Xcode 项目来调用一个 C 库,比如 SQLite,我们需要(1)添加一个 Bridge-Header.h 文件引用 C 头,比如 #import "sqlite3.h",(2)在项目设置中向 目标 -C 桥接头添加 Bridge-Header.h,(3)向 Link Binary With Library目标设置添加 libsqlite3.tbd

Sqlite.org"SQLite in 5 minutes or less"示例是在 Swift Xcode7项目 给你中实现的。

应用代理,迅捷

func createDatabase()
{
var path:Array=NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
let directory:String=path[0]
let DBpath=(directory as NSString).appendingPathComponent("Food.sqlite")


print(DBpath)


if (FileManager.default.fileExists(atPath: DBpath))
{
print("Successfull database create")
}
else
{
let pathfrom:String=(Bundle.main.resourcePath! as NSString).appendingPathComponent("Food.sqlite")


var success:Bool
do {
try FileManager.default.copyItem(atPath: pathfrom, toPath: DBpath)
success = true
} catch _ {
success = false
}


if !success
{
print("database not create ")
}
else
{
print("Successfull database new create")
}
}
}

数据库 Swift

import UIKit


class database: NSObject
{
func databasePath() -> NSString
{
var path:Array=NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
let directory:String=path[0]
let DBpath=(directory as NSString).appendingPathComponent("Food.sqlite")


if (FileManager.default.fileExists(atPath: DBpath))
{
return DBpath as NSString
}
return DBpath as NSString
}


func ExecuteQuery(_ str:String) -> Bool
{
var result:Bool=false
let DBpath:String=self.databasePath() as String


var db: OpaquePointer? = nil
var stmt:OpaquePointer? = nil


let strExec=str.cString(using: String.Encoding.utf8)


if (sqlite3_open(DBpath, &db)==SQLITE_OK)
{
if (sqlite3_prepare_v2(db, strExec! , -1, &stmt, nil) == SQLITE_OK)
{
if (sqlite3_step(stmt) == SQLITE_DONE)
{
result=true
}
}
sqlite3_finalize(stmt)
}
sqlite3_close(db)


return result
}


func SelectQuery(_ str:String) -> Array<Dictionary<String,String>>
{
var result:Array<Dictionary<String,String>>=[]
let DBpath:String=self.databasePath() as String


var db: OpaquePointer? = nil
var stmt:OpaquePointer? = nil


let strExec=str.cString(using: String.Encoding.utf8)


if ( sqlite3_open(DBpath,&db) == SQLITE_OK)
{
if (sqlite3_prepare_v2(db, strExec! , -1, &stmt, nil) == SQLITE_OK)
{
while (sqlite3_step(stmt) == SQLITE_ROW)
{
var i:Int32=0
let icount:Int32=sqlite3_column_count(stmt)


var dict=Dictionary<String, String>()


while i < icount
{
let strF=sqlite3_column_name(stmt, i)
let strV = sqlite3_column_text(stmt, i)


let rFiled:String=String(cString: strF!)
let rValue:String=String(cString: strV!)
//let rValue=String(cString: UnsafePointer<Int8>(strV!))


dict[rFiled] = rValue


i += 1
}
result.insert(dict, at: result.count)
}
sqlite3_finalize(stmt)
}


sqlite3_close(db)
}
return result
}


func AllSelectQuery(_ str:String) -> Array<Model>
{
var result:Array<Model>=[]
let DBpath:String=self.databasePath() as String


var db: OpaquePointer? = nil
var stmt:OpaquePointer? = nil


let strExec=str.cString(using: String.Encoding.utf8)


if ( sqlite3_open(DBpath,&db) == SQLITE_OK)
{
if (sqlite3_prepare_v2(db, strExec! , -1, &stmt, nil) == SQLITE_OK)
{
while (sqlite3_step(stmt) == SQLITE_ROW)
{
let mod=Model()


mod.id=String(cString: sqlite3_column_text(stmt, 0))
mod.image=String(cString: sqlite3_column_text(stmt, 1))
mod.name=String(cString: sqlite3_column_text(stmt, 2))
mod.foodtype=String(cString: sqlite3_column_text(stmt, 3))
mod.vegtype=String(cString: sqlite3_column_text(stmt, 4))
mod.details=String(cString: sqlite3_column_text(stmt, 5))


result.insert(mod, at: result.count)
}
sqlite3_finalize(stmt)
}
sqlite3_close(db)
}
return result
}


}

ModelSwift

import UIKit




class Model: NSObject
{
var uid:Int = 0
var id:String = ""
var image:String = ""
var name:String = ""
var foodtype:String = ""
var vegtype:String = ""
var details:String = ""
var mealtype:String = ""
var date:String = ""
}

存取资料库:

let DB=database()
var mod=Model()

返回文章页面数据库查询火:

var DailyResult:Array<Model> = DB.AllSelectQuery("select * from food where foodtype == 'Sea Food' ORDER BY name ASC")

您也可以轻松地使用单吨类快速配置 SQLite。

参考

Https://github.com/hasyapanchasara/sqlite_singlemanagerclass

方法创建数据库

func methodToCreateDatabase() -> NSURL?{}

方法插入、更新和删除数据

func methodToInsertUpdateDeleteData(strQuery : String) -> Bool{}

Method to select data

func methodToSelectData(strQuery : String) -> NSMutableArray{}

您可以在 Swift for SQLite 中使用此库 Https://github.com/pmurphyjam/sqlitedemo

SQLiteDemo

使用 Swift 和用 Swift 编写的 SQLDataAccess 类进行 SQLite 演示

Adding to Your Project

您只需要将三个文件添加到项目中 * SQLDataAccess.swift * DataConstants.swift * 桥头堡 Bridging-Header must be set in your Xcode's project 'Objective-C Bridging Header' under 'Swift Compiler - General'

使用示例

只需按照 ViewController.swift 中的代码查看如何使用 SQLDataAccess.swift 编写简单的 SQL 首先,您需要打开您处理的 SQLite 数据库

    let db = SQLDataAccess.shared
db.setDBName(name:"SQLite.db")
let opened = db.openConnection(copyFile:true)

如果 openConnection 成功了,现在您可以对 Table AppInfo 执行一个简单的插入操作

    //Insert into Table AppInfo
let status = db.executeStatement("insert into AppInfo (name,value,descrip,date) values(?,?,?,?)",
”SQLiteDemo","1.0.2","unencrypted",Date())
if(status)
{
//Read Table AppInfo into an Array of Dictionaries
let results = db.getRecordsForQuery("select * from AppInfo ")
NSLog("Results = \(results)")
}

看看这有多简单!

ExecuteStatement 中的第一个术语是 SQL as String,接下来的所有术语都是任意类型的可变参数列表,是 Array 中的参数。所有这些术语在 SQL 参数列表中都用逗号分隔。可以在续集语句之后输入 String、 Integers、 Date’s 和 Blobs,因为所有这些术语都被认为是续集的参数。可变参数数组使您可以方便地在一个 ExecuteStatement 或 getRecordsForQuery 调用中输入所有的续集。如果没有任何参数,则不要在 SQL 之后输入任何内容。

Result 数组是一个 Array of Dictionary,其中“ key”是表列名,“ value”是从 SQLite 获得的数据。您可以使用 for 循环轻松地迭代此数组,或直接打印出来,或将这些 Dictionary 元素分配给您在视图控制器中用于模型使用的自定义数据对象类。

    for dic in results as! [[String:AnyObject]] {
print(“result = \(dic)”)
}

SQLDataAccess 将存储文本、双精度数、浮点数、 blob、日期、整数和长整数。 对于 Blobs,您可以存储二进制文件、 varbinary 文件、 blob 文件。

For Text you can store char, character, clob, national varying character, native character, nchar, nvarchar, varchar, variant, varying character, text.

For Dates you can store datetime, time, timestamp, date.

For Integers you can store bigint, bit, bool, boolean, int2, int8, integer, mediumint, smallint, tinyint, int.

双精度可以存储小数、双精度、浮点、数值、实数、双精度。双精度最高。

You can even store Nulls of type Null.

In ViewController.swift a more complex example is done showing how to insert a Dictionary as a 'Blob'. In addition SQLDataAccess 理解本地 Swift Date () ,因此您可以插入这些对象而不需要进行转换,它将把它们转换为文本并存储它们, 并在检索时将它们从文本转换回 Date。

当然,SQLite 的真正强大之处在于它的 Transaction 功能。在这里,您可以使用参数对400条 SQL 语句进行排队 然后把它们一次性全部放进去,因为速度很快,所以非常强大。Swift 还向您展示了如何做到这一点的示例。 您实际上所做的就是创建一个名为“ sqlAndParams”的字典数组,在这个 Array 中存储具有两个键的字典 “ SQL”表示字符串后续语句或查询,“ PARAMS”表示 SQLite 对该查询理解的本机对象的 Array。 Each 'sqlParams' which is an individual Dictionary of sequel query plus parameters is then stored in the 'sqlAndParams' Array. 创建了这个数组之后,只需调用。

    let status = db.executeTransaction(sqlAndParams)
if(status)
{
//Read Table AppInfo into an Array of Dictionaries for the above Transactions
let results = db.getRecordsForQuery("select * from AppInfo ")
NSLog("Results = \(results)")
}

此外,所有 ExecuteStatement 和 getRecordsForQuery 方法都可以通过简单的 String for SQL 查询和 Array for 查询所需的参数来完成。

    let sql : String = "insert into AppInfo (name,value,descrip) values(?,?,?)"
let params : Array = ["SQLiteDemo","1.0.0","unencrypted"]
let status = db.executeStatement(sql, withParameters: params)
if(status)
{
//Read Table AppInfo into an Array of Dictionaries for the above Transactions
let results = db.getRecordsForQuery("select * from AppInfo ")
NSLog("Results = \(results)")
}

还存在 Objective-C 版本,称为相同的 SQLDataAccess,因此现在可以选择用 Objective-C 或 Swift 编写续集。 此外,SQLDataAccess 也可以使用 SQLCipher,目前的代码尚未设置为使用 SQLCipher,但这很容易做到,并且 在 SQLDataAccess 的 Objective-C 版本中,实际上提供了一个示例。

SQLDataAccess 是一个非常快速有效的类,可以用来替代实际上只使用 SQLite 作为底层数据的 CoreData 在没有 CoreData 所有核心数据完整性故障的情况下存储 CoreData。

这是迄今为止我在 Swift: https://github.com/stephencelis/SQLite.swift中使用过的最好的 SQLite 库

看看这些代码示例,比 C API 干净多了:

import SQLite


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


let users = Table("users")
let id = Expression<Int64>("id")
let name = Expression<String?>("name")
let email = Expression<String>("email")


try db.run(users.create { t in
t.column(id, primaryKey: true)
t.column(name)
t.column(email, unique: true)
})
// CREATE TABLE "users" (
//     "id" INTEGER PRIMARY KEY NOT NULL,
//     "name" TEXT,
//     "email" TEXT NOT NULL UNIQUE
// )


let insert = users.insert(name <- "Alice", email <- "alice@mac.com")
let rowid = try db.run(insert)
// INSERT INTO "users" ("name", "email") VALUES ('Alice', 'alice@mac.com')


for user in try db.prepare(users) {
print("id: \(user[id]), name: \(user[name]), email: \(user[email])")
// id: 1, name: Optional("Alice"), email: alice@mac.com
}
// SELECT * FROM "users"


let alice = users.filter(id == rowid)


try db.run(alice.update(email <- email.replace("mac.com", with: "me.com")))
// UPDATE "users" SET "email" = replace("email", 'mac.com', 'me.com')
// WHERE ("id" = 1)


try db.run(alice.delete())
// DELETE FROM "users" WHERE ("id" = 1)


try db.scalar(users.count) // 0
// SELECT count(*) FROM "users"

文档还说,“ SQLite.swift 也可以作为一个轻量级的、对 Swift 友好的 C API 包装器工作”,接下来是一些示例。