Swiftコードを使用して、アプリのSQLiteデータベースにアクセスする方法を探しています。
Objective CでSQLite Wrapperを使用し、ブリッジングヘッダーを使用できることは知っていますが、このプロジェクトを完全にSwiftで行うことができます。これを行う方法はありますか?もしそうであれば、誰かがクエリを送信する方法、行を取得する方法などを示す参照を私に指すことができますか?
おそらく多くのSQLiteラッパーの1つを使用する必要があります(私は FMDB を好みます)が、SQLiteライブラリを自分で呼び出す方法を知りたい場合は、次のようにします。
Swiftプロジェクトを構成して、SQLite C呼び出しを処理します。 Xcode 9を使用している場合、次のことが簡単にできます。
import SQLite3
Xcodeの以前のバージョンでは、次のことができます。
プロジェクトへのブリッジングヘッダーファイルを作成します。 CocoaとObjective-CでのSwiftの使用 のObjective-CのSwiftへのインポートセクションを参照してください。このブリッジングヘッダーはsqlite3.h
をインポートする必要があります。
#import <sqlite3.h>
libsqlite3.tbd
(またはさらに古いバージョンの場合はlibsqlite3.dylib
)をプロジェクトに追加します。
データベースを作成/開きます。
let fileURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
.appendingPathComponent("test.sqlite")
// open database
var db: OpaquePointer?
if sqlite3_open(fileURL.path, &db) != SQLITE_OK {
print("error opening database")
}
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)")
}
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)
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)")
}
準備済みステートメントに関連するメモリを回復する準備済みステートメントを完成させます。
if sqlite3_finalize(statement) != SQLITE_OK {
let errmsg = String(cString: sqlite3_errmsg(db)!)
print("error finalizing prepared statement: \(errmsg)")
}
statement = nil
テーブルから値を選択するための新しいステートメントを準備し、値を取得してループします。
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
データベースを閉じる:
if sqlite3_close(db) != SQLITE_OK {
print("error closing database")
}
db = nil
Swift 2については、 この回答の以前のリビジョン を参照してください。
できる最善の方法は、ブリッジングヘッダー内に動的ライブラリをインポートすることです。
#import <sqlite3.h>
を上部に追加しますその後、Swiftコードからsqlite3_open
などのすべてのcメソッドにアクセスできるようになります。
ただし、単に FMDB を使用し、ブリッジヘッダーを介してインポートすることもできます。これは、sqliteのよりオブジェクト指向のラッパーです。 Swiftでは、Cのポインターと構造体を扱うのは面倒です。
私も、以前Objective-Cで行っていたのと同じ方法でSQLiteとやり取りする方法を探していました。確かに、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 */
SwiftData と呼ばれるSwiftで完全に記述されたエレガントなSQLiteライブラリを作成しました。
その機能の一部は次のとおりです。
「変更」を実行する簡単な方法を提供します(例: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
}
および「クエリ」(例: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)")
}
}
}
さらに多くの機能とともに!
あなたはそれをチェックアウトすることができます こちら
AppDelegate.Swift
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")
}
}
}
Database.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
}
}
Model.Swift
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")
Swift 2およびSwift 3:のさらに別のSQLiteラッパー3: http://github.com/groue/GRDB.Swift
特徴:
ccgus/fmdb のユーザーに馴染みのあるAPI
Swift標準ライブラリを活用する低レベルのSQLite API
SQLアレルギー開発者向けのかなりSwiftクエリインターフェイス
SQLite WALモードのサポート、および追加のパフォーマンスのための同時データベースアクセス
結果セットをラップし、朝食にカスタムSQLクエリを処理し、基本的なCRUD操作を提供するRecordクラス
Swift型の自由度:データに適合する適切なSwift型を選択します。必要に応じてInt64を使用するか、便利なIntを使い続けます。 NSDateまたはNSDateComponentsを保存して読み取ります。離散データ型のSwift列挙型を宣言します。独自のデータベース変換可能な型を定義します。
データベースの移行
時々、 sqlite.org に示されている "5分以内のSQLite" アプローチのSwiftバージョンで十分です。 「5分以内」のアプローチでは、sqlite3_exec()
、sqlite3_prepare()
、sqlite3_step()
、およびsqlite3_column()
の便利なラッパーであるsqlite3_finalize()
を使用します。
Swift 2.2は、グローバルな非インスタンスプロシージャcallback
または非キャプチャリテラルクロージャ{}
としてsqlite3_exec()
func
関数ポインタを直接サポートできます。
読み取り可能な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
}
SQLiteなどのCライブラリを呼び出すXcodeプロジェクトを準備するには、(1)#import "sqlite3.h"
などのBridging-Header.hファイル参照Cヘッダーを追加するか、(2)Bridging-Header.hをプロジェクト設定のObjective-Cブリッジヘッダー、および(3)libsqlite3.tbd
をLink Binary with Libraryに追加ターゲット設定。
sqlite.org の "5分以内のSQLite" の例は、Swift Xcode7プロジェクトに実装されています here 。
このライブラリは、SQLiteのSwiftで使用できます https://github.com/pmurphyjam/SQLiteDemo
Swiftで記述されたSQLDataAccessクラスでSwiftを使用したSQLiteデモ
プロジェクトに追加するのに必要なファイルは3つだけです* SQLDataAccess.Swift * DataConstants.Swift * Bridging-Header.h
ViewController.Swiftのコードに従って、SQLDataAccess.Swiftを使用して簡単なSQLを記述する方法を確認します。最初に、処理するSQLiteデータベースを開く必要があります。
```Swift
let db = SQLDataAccess.shared
db.setDBName(name:"SQLite.db")
let opened = db.openConnection(copyFile:true)
```
OpenConnectionが成功した場合、テーブルAppInfoへの簡単な挿入ができるようになりました
```Swift
//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)")
}
```
それがいかに簡単かを見てください!
Db.executeStatementの最初の用語は文字列としてのSQLです。その後に続く用語はすべてAny型の可変引数リストであり、配列内のパラメーターです。これらすべての用語は、SQL引数のリスト内でコンマで区切られています。これらの用語はすべて続編のパラメーターと見なされるため、文字列、整数、日付、ブロブを続編ステートメントの直後に入力できます。可変引数の配列は、1つのexecuteStatementまたはgetRecordsForQuery呼び出しですべての続編を入力するのに便利です。パラメータがない場合は、SQLの後に何も入力しないでください。
結果の配列は辞書の配列で、「キー」はテーブルの列名、「値」はSQLiteから取得したデータです。 forループでこの配列を簡単に反復したり、直接印刷したり、モデルの消費のためにView Controllerで使用するカスタムデータオブジェクトクラスにこれらのDictionary要素を割り当てることができます。
```Swift
for dic in results as! [[String:AnyObject]] {
print(“result = \(dic)”)
}
```
SQLDataAccessは、text、double、float、blob、Date、integer、long long integerを保存します。 Blobには、バイナリ、varbinary、blobを保存できます。
テキストの場合、char、character、clob、各国の可変文字、ネイティブ文字、nchar、nvarchar、varchar、variant、variing character、textを保存できます。
日付には、日時、時刻、タイムスタンプ、日付を保存できます。
整数の場合、bigint、bit、bool、boolean、int2、int8、integer、mediumint、smallint、tinyint、intを格納できます。
Doubleの場合、10進数、倍精度、浮動小数点、数値、実数、倍精度を格納できます。 Doubleが最も精度が高くなります。
Null型のNullも保存できます。
ViewController.Swiftでは、より複雑な例が実行され、辞書を「Blob」として挿入する方法が示されています。さらに、SQLDataAccessはネイティブのSwift Date()を理解するため、これらのオブジェクトを変換せずに挿入でき、テキストに変換して保存し、取得時にテキストから日付に変換します。
もちろん、SQLiteの真の力はトランザクション機能です。ここでは、パラメーターを使用して文字通り400個のSQLステートメントをキューに入れ、それらをすべて一度に挿入できます。これは非常に高速であるため、非常に強力です。 ViewController.Swiftは、これを行う方法の例を示しています。あなたが本当にしているのは、「sqlAndParams」と呼ばれる辞書の配列を作成することです。この配列には、文字列の続きのステートメントまたはクエリ用の2つのキー「SQL」と、ネイティブオブジェクトの配列である「PARAMS」を含む辞書を格納しますそのクエリを理解します。その後、各クエリとパラメータの個別のディクショナリである各「sqlParams」は、「sqlAndParams」配列に格納されます。この配列を作成したら、呼び出すだけです。
```Swift
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メソッドは、SQLクエリ用の単純な文字列と、クエリに必要なパラメータ用の配列を使用して実行できます。
```Swift
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で動作します。現在のコードはまだ動作するようにセットアップされていませんが、実行するのは非常に簡単です。これを行う方法の例は、SQLDataAccessのObjective-Cバージョンにあります。
SQLDataAccessは非常に高速で効率的なクラスであり、CoreDataの代わりに使用できます。CoreDataは、CoreDataに付属するすべてのCoreDataコアデータ整合性フォールトクラッシュなしでSQLiteを基礎データストアとして使用するだけです。
これは、私がSwiftで使用した最高のSqliteライブラリです: https://github.com/stephencelis/SQLite.Swift
コード例を見てください。 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 <- "[email protected]")
let rowid = try db.run(insert)
// INSERT INTO "users" ("name", "email") VALUES ('Alice', '[email protected]')
for user in try db.prepare(users) {
print("id: \(user[id]), name: \(user[name]), email: \(user[email])")
// id: 1, name: Optional("Alice"), email: [email protected]
}
// 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はC APIの軽量でスウィフトフレンドリーなラッパーとしても機能する」と記載されており、その例をいくつか示します。
Swiftプロジェクトを構成して、SQLite C呼び出しを処理します。
プロジェクトへのブリッジングヘッダーファイルを作成します。 CocoaおよびObjective-CでSwiftを使用するのSwiftセクションへのObjective-Cのインポートを参照してください。このブリッジングヘッダーはsqlite3.hをインポートする必要があります。
Libsqlite3.0.dylibをプロジェクトに追加します。ライブラリ/フレームワークをプロジェクトに追加することに関するAppleのドキュメントを参照してください。
そして、次のコードを使用しました
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でSQLiteを簡単に構成することもできます。
参照
https://github.com/hasyapanchasara/SQLite_SingleManagerClass
データベースの作成方法
func methodToCreateDatabase() -> NSURL?{}
データを挿入、更新、削除する方法
func methodToInsertUpdateDeleteData(strQuery : String) -> Bool{}
データを選択する方法
func methodToSelectData(strQuery : String) -> NSMutableArray{}
Swiftで記述されたSQLite3ラッパーライブラリ と記述しました。
これは実際には非常に単純なAPIを備えた非常に高レベルのラッパーですが、とにかく、低レベルのC相互運用コードがあり、C相互運用を示すためにここに(簡略化した)部分を投稿します。
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
}
この低レベルラッパーの完全なソースコードが必要な場合は、これらのファイルを参照してください。