1. ホーム
  2. sqlite

[解決済み] Swift で SQLite データベースにアクセスする

2022-10-31 20:25:36

質問

Swiftのコードで、アプリ内のSQLiteデータベースにアクセスする方法を探しています。

Objective C で SQLite Wrapper を使用し、ブリッジングヘッダーを使用できることを知っていますが、私はむしろ、このプロジェクトを完全に Swift で行うことができるようにしたいと思っています。これを行う方法はありますか、もしそうなら、誰かがクエリを送信し、行を取得する方法などを示す参照に私を指し示すことができますか?

どのように解決するのですか?

おそらく多くの SQLite ラッパーのうちの 1 つを使うべきですが、SQLite ライブラリーを自分で呼び出す方法を知りたかったら、そうするでしょう。

  1. SQLite の C 呼び出しを処理するために Swift プロジェクトを構成します。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() に渡して解放する必要があります。

  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. 使用方法 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)
    
    
  5. 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)")
    }
    
    
  6. プリペアドステートメントをファイナライズして、そのプリペアドステートメントに関連するメモリを回復します。

    if sqlite3_finalize(statement) != SQLITE_OK {
        let errmsg = String(cString: sqlite3_errmsg(db)!)
        print("error finalizing prepared statement: \(errmsg)")
    }
    
    statement = nil
    
    
  7. テーブルから値を選択するための新しいステートメントを用意し、値を取得するループを実行します。

    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. データベースを閉じます。

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

Swift 2 およびそれ以前のバージョンの Xcode については この回答の以前のリビジョン .