一尘不染

在Swift中访问SQLite数据库

swift

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

我知道我可以在Objective
C中使用SQLite包装器并使用桥接头,但是我希望能够完全在Swift中完成此项目。如果可以的话,有没有办法做到这一点,有人可以将我指向一个引用,该引用显示了如何提交查询,检索行等。


阅读 267

收藏
2020-07-07

共1个答案

一尘不染

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

  1. 配置您的Swift项目以处理SQLite C调用。如果使用Xcode 9或更高版本,则只需执行以下操作:

    import SQLite3
    
  2. 创建/打开数据库。

        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()不再需要时释放。

  1. 使用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)")
    }
  1. 使用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)")
    }

注意,它使用可以如下实现的SQLITE_TRANSIENT常量:

        internal let SQLITE_STATIC = unsafeBitCast(0, to: sqlite3_destructor_type.self)
    internal let SQLITE_TRANSIENT = unsafeBitCast(-1, to: sqlite3_destructor_type.self)
  1. 重置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)")
    }
  1. 完成准备好的语句以恢复与该准备好的语句关联的内存:
        if sqlite3_finalize(statement) != SQLITE_OK {
        let errmsg = String(cString: sqlite3_errmsg(db)!)
        print("error finalizing prepared statement: \(errmsg)")
    }

    statement = nil
  1. 准备用于从表中选择值的新语句,并通过检索值循环:
        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
  1. 关闭数据库:
        if sqlite3_close(db) != SQLITE_OK {
        print("error closing database")
    }

    db = nil
2020-07-07