我正在寻找一种方法来使用Swift代码访问我的应用程序中的SQLite数据库.
我知道我可以在Objective C中使用SQLite Wrapper并使用桥接头,但我宁愿能够完全在Swift中完成这个项目.有没有办法做到这一点,如果是这样,有人可以指向我的参考,显示如何提交查询,检索行等?
Rob*_*Rob 135
虽然你应该使用众多SQLite包装器中的一个(我更喜欢FMDB,我自己),如果你想知道如何自己调用SQLite库,你会:
配置Swift项目以处理SQLite C调用.如果使用Xcode 9,您只需执行以下操作:
import SQLite3
Run Code Online (Sandbox Code Playgroud)
在早期版本的Xcode中,您可以:
为项目创建桥接头文件.请参阅使用Swift with Cocoa和Objective-C将Importing-C导入到Swift部分.此桥接标头应导入:sqlite3.h
#import <sqlite3.h>
Run Code Online (Sandbox Code Playgroud)将libsqlite3.tbd(或者甚至更旧的版本libsqlite3.dylib)添加到项目中:
创建/打开数据库.
let fileURL = try! FileManager.default
.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
.appendingPathComponent("test.sqlite")
// open database
var db: OpaquePointer?
if sqlite3_open(fileURL.path, &db) != SQLITE_OK {
print("error opening database")
}
Run Code Online (Sandbox Code Playgroud)使用sqlite3_exec执行SQL(如创建表).
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)")
}
Run Code Online (Sandbox Code Playgroud)用于使用我们将绑定值的占位符sqlite3_prepare_v2准备SQL ?.
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)")
}
Run Code Online (Sandbox Code Playgroud)
注意,使用可以如下实现的SQLITE_TRANSIENT常量:
internal let SQLITE_STATIC = unsafeBitCast(0, to: sqlite3_destructor_type.self)
internal let SQLITE_TRANSIENT = unsafeBitCast(-1, to: sqlite3_destructor_type.self)
Run Code Online (Sandbox Code Playgroud)重置SQL以插入另一个值.在这个例子中,我将插入一个NULL值:
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)")
}
Run Code Online (Sandbox Code Playgroud)完成准备好的语句以恢复与该预准备语句相关的内存:
if sqlite3_finalize(statement) != SQLITE_OK {
let errmsg = String(cString: sqlite3_errmsg(db)!)
print("error finalizing prepared statement: \(errmsg)")
}
statement = nil
Run Code Online (Sandbox Code Playgroud)准备新语句以从表中选择值并循环检索值:
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
Run Code Online (Sandbox Code Playgroud)关闭数据库:
if sqlite3_close(db) != SQLITE_OK {
print("error closing database")
}
db = nil
Run Code Online (Sandbox Code Playgroud)对于Swift 2,请参阅此答案的先前版本.
dre*_*wag 18
您可以做的最好的事情是在桥接头中导入动态库:
#import <sqlite3.h>到顶部然后,您就可以sqlite3_open从swift代码中访问所有c方法.
但是,您可能只想使用FMDB并通过桥接头导入它,因为这是一个更面向对象的sqlite包装器.在Swift中处理C指针和结构将很麻烦.
Chr*_*son 11
我也在寻找一种与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 */
Run Code Online (Sandbox Code Playgroud)
小智 5
我创建了一个优雅的完全用Swift编写的SQLite库,称为SwiftData。
它的一些功能是:
它提供了一种执行“更改”(例如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
}
Run Code Online (Sandbox Code Playgroud)
和“查询”(例如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)")
}
}
}
Run Code Online (Sandbox Code Playgroud)
随着更多的功能!
你可以在这里查看
Swift 2 和 Swift 3 的另一个 SQLite 包装器:http://github.com/groue/GRDB.swift
特征:
ccgus/fmdb用户看起来很熟悉的 API
利用 Swift 标准库的低级 SQLite API
为 SQL 过敏的开发人员提供的漂亮的 Swift 查询界面
支持 SQLite WAL 模式和并发数据库访问以获得额外性能
一个 Record 类,它包装结果集,将您的自定义 SQL 查询当早餐,并提供基本的 CRUD 操作
Swift 类型自由:选择适合您的数据的正确 Swift 类型。需要时使用 Int64,或者坚持使用方便的 Int。存储和读取 NSDate 或 NSDateComponents。为离散数据类型声明 Swift 枚举。定义您自己的数据库可转换类型。
数据库迁移