programing

Swift에서 SQLite 데이터베이스 액세스

instargram 2023. 8. 25. 23:14
반응형

Swift에서 SQLite 데이터베이스 액세스

앱에서 Swift 코드로 SQLite 데이터베이스에 액세스할 수 있는 방법을 찾고 있습니다.

나는 목표 C에서 SQLite 래퍼를 사용하고 브리징 헤더를 사용할 수 있다는 것을 알고 있지만, 이 프로젝트를 전적으로 Swift에서 수행할 수 있기를 원합니다.이렇게 할 수 있는 방법이 있습니까? 그렇다면 누군가 쿼리 제출, 행 검색 등을 보여주는 참조를 알려줄 수 있습니까?

많은 SQLite 래퍼 중 하나를 사용해야 하지만 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 설명서는 메모리 누수를 방지하기 위해 반드시 그렇게 해야 함을 명시합니다.

    데이터베이스 연결 핸들을 열 때 오류가 발생하든 발생하지 않든 데이터베이스 연결 핸들과 관련된 리소스는 더 이상 필요하지 않을 때 에 전달하여 해제해야 합니다.

  3. 사용하다sqlite3_execSQL을 수행합니다(예: 테이블 만들기).

    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을 사용하여 합니다.?값을 바인딩할 자리 표시자입니다.

    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에 대해서는 이 답변의 이전 버전을 참조하십시오.

브리지 헤더 내의 동적 라이브러리를 가져오는 것이 최선입니다.

  1. libsqlite3.dylib을 "라이브러리로 이진 연결" 빌드 단계에 추가합니다.
  2. "Bridging-Header" 성합니다작를와 "add h" 추가및.#import <sqlite3.h> 위에
  3. "Bridging-Header"를 설정합니다.h"는 "Swift Compiler - Code Generation"의 빌드 설정에서 "Objective-C Bridging Header" 설정에 대한 것입니다.

은 그면다같모은든수 c있액다니습세법과 같은 모든 c 방법에 접근할 수 있을 것입니다.sqlite3_open당신의 신속한 코드로부터.

그러나 FMDB를 사용하고 브리지 헤더를 통해 가져오기를 원할 수도 있습니다. 이는 sqlite의 객체 지향 래퍼이기 때문입니다.스위프트에서 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 라이브러리를 만들었습니다.

일부 기능은 다음과 같습니다.

  • 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
}

및 '쿼리'(예: 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)")
        }
    }
}

더 많은 기능과 함께!

여기서 확인할 수 있습니다.

Swift 2와 Swift 3의 또 다른 SQLite 래퍼: http://github.com/groue/GRDB.swift

특징:

  • ccgus/fmdb 사용자에게 친숙한 API

  • Swift 표준 라이브러리를 활용하는 낮은 수준의 SQLite API

  • SQL-알레르기 개발자를 위한 매우 빠른 쿼리 인터페이스

  • SQLite WAL 모드 지원 및 추가 성능을 위한 동시 데이터베이스 액세스

  • 결과 집합을 래핑하고, 아침 식사로 사용자 정의 SQL 쿼리를 먹고, 기본적인 CRUD 작업을 제공하는 Record 클래스

  • 신속한 유형 자유: 데이터에 적합한 최적의 Swift 유형을 선택합니다.필요할 때 Int64를 사용하거나 편리한 Int를 사용합니다.NSDate 또는 NSDate 구성 요소를 저장하고 읽습니다.개별 데이터 유형에 대해 Swift 열거형을 선언합니다.고유한 데이터베이스 변환 가능 유형을 정의합니다.

  • 데이터베이스 마이그레이션

  • 속도: https://github.com/groue/GRDB.swift/wiki/Performance

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
}

}

모델.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에서 사용한 것 중 가장 좋은 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 <- "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는 C API를 통해 경량의 Swift 친화적인 래퍼로도 작동합니다."라고 나와 있으며, 다음은 그 예입니다.

이 라이브러리는 Swift for SQLite https://github.com/pmurphyjam/SQLiteDemo 에서 사용할 수 있습니다.

SQLiteDemo

Swift로 작성된 SQLDataAccess 클래스와 함께 Swift를 사용한 SQLite 데모

프로젝트에 추가

프로젝트에 추가하려면 3개의 파일만 필요합니다 * SQLDataAccess.swift * DataConstants.swift * Bridging-Header.h Bridging-Header는 Xcode의 프로젝트 'Objective-C Bridging Header - General'에서 설정해야 합니다.

사용 예

ViewController.swift의 코드에 따라 SQLDataAccess.swift를 사용하여 간단한 SQL을 작성하는 방법을 확인하십시오. 먼저 처리 중인 SQLite 데이터베이스를 열어야 합니다.

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

openConnection이 성공한 경우 TableAppInfo에 간단히 삽입할 수 있습니다.

    //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 as String이고, 이어지는 모든 용어는 Any 유형의 변수 인수 목록이며, 배열에서 매개 변수입니다.SQL 인수 목록에서 이러한 모든 용어는 쉼표로 구분됩니다.이러한 용어는 모두 후속 문장의 매개 변수로 간주되므로 후속 문장 직후에 문자열, 정수, 날짜 및 블롭을 입력할 수 있습니다.변수 인수 배열을 사용하면 executeStatement 또는 getRecordsForQuery 호출 한 번으로 모든 후속편을 편리하게 입력할 수 있습니다.매개 변수가 없으면 SQL 뒤에 아무것도 입력하지 마십시오.

결과 배열은 사전 배열입니다. 여기서 'key'는 테이블 열 이름이고 'value'는 SQLite에서 가져온 데이터입니다.for 루프를 사용하여 이 배열을 쉽게 반복하거나 직접 인쇄하거나 이러한 사전 요소를 View Controller에서 모델 사용에 사용하는 사용자 지정 데이터 개체 클래스에 할당할 수 있습니다.

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

SQLDataAccess는 텍스트, 이중, 부동, 블롭, 날짜, 정수 및 긴 정수를 저장합니다.Blobs의 경우 이진, varbinary, blob을 저장할 수 있습니다.

텍스트의 경우 char, char, clob, 국가별 다양한 문자, 네이티브 문자, nchar, nvarchar, varchar, variant, variant, variant, variant char, text를 저장할 수 있습니다.

날짜의 경우 날짜 시간, 시간, 타임스탬프, 날짜를 저장할 수 있습니다.

정수의 경우 bigint, 비트, boolean, int2, int8, 정수, mediumint, smallint, tinyint, int를 저장할 수 있습니다.

이중의 경우 소수점, 이중 정밀도, 부동 소수점, 숫자, 실수, 이중을 저장할 수 있습니다.이중이 가장 정밀합니다.

Null 유형의 Null도 저장할 수 있습니다.

ViewController.swift에서는 사전을 '블롭'으로 삽입하는 방법을 보여주는 보다 복잡한 예제가 수행됩니다.또한 SQLDataAccess는 기본 SwiftDate()를 이해하므로 변환하지 않고 이러한 개체를 삽입할 수 있습니다. 그러면 이 개체를 텍스트로 변환하여 저장하고 검색하면 텍스트에서 날짜로 다시 변환합니다.

물론 SQLite의 진정한 힘은 트랜잭션 기능입니다.여기서는 400개의 SQL 문을 문자 그대로 매개 변수로 큐에 넣고 한 번에 모두 삽입할 수 있습니다. 이는 매우 빠른 속도이기 때문에 매우 강력합니다.ViewController.swift는 이 작업을 수행하는 방법의 예도 보여 줍니다.당신이 실제로 하고 있는 것은 'sqlAndParams'라는 사전 배열을 만드는 것뿐입니다. 이 배열에는 String 후속 문장이나 쿼리에 대한 두 개의 키 'SQL'과 SQLite가 해당 쿼리에 대해 이해하는 기본 개체의 배열인 'PARAMS'가 포함되어 있습니다.후속 쿼리와 매개 변수의 개별 사전인 각 'sqlParams'는 'sqlAndParams' 배열에 저장됩니다.이 배열을 만든 후에는 전화만 하면 됩니다.

    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를 사용하여 수행할 수 있습니다.

    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는 매우 빠르고 효율적인 클래스로, CoreData와 함께 제공되는 모든 CoreData 핵심 데이터 무결성 장애 없이 SQLite를 기본 데이터 저장소로 사용하는 CoreData 대신 사용할 수 있습니다.

저는 Swift로 작성된 SQLite3 래퍼 라이브러리를 작성했습니다.

이것은 사실 매우 간단한 API를 가진 매우 높은 수준의 래퍼이지만, 어쨌든, 낮은 수준의 C 인터-op 코드를 가지고 있고, 저는 여기에 C 인터-op을 보여주기 위해 (간단한) 부분을 게시합니다.

    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 C 호출을 처리하도록 Swift 프로젝트를 구성합니다.

프로젝트에 대한 브리징 헤더 파일을 만듭니다.코코아 및 목표-C와 함께 스위프트 사용의 목표-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
        }
    }
}

때로는 sqlite.org 에 나와 있는 "SQLite in 5 minutes" 접근 방식의 Swift 버전으로도 충분합니다."5분 이내" 접근 방식은 다음을 사용합니다.sqlite3_exec()그것은 편리한 포장지입니다.sqlite3_prepare(),sqlite3_step(),sqlite3_column(),그리고.sqlite3_finalize().

Swift 2.2는 다음을 직접 지원할 수 있습니다.sqlite3_exec() callback함수 포인터를 글로벌 비슬래시 프로시저로 사용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) 다음과 같은 Bridging-Header.h 파일 참조 C 헤더를 추가해야 합니다.#import "sqlite3.h"(2) 프로젝트 설정에서 Bridging-Header.h를 Objective-C Bridging Header에 추가하고 (3) 추가libsqlite3.tbd바이너리와 라이브러리 대상 설정을 연결합니다.

sqlite.org "SQLite in 5 minutes" 예제는 Swift Xcode7 프로젝트에서 구현됩니다.

single ton 클래스를 사용하여 swift로 SQLite를 쉽게 구성할 수도 있습니다.

참조하다

https://github.com/hasyapanchasara/SQLite_SingleManagerClass

데이터베이스를 만드는 방법

func methodToCreateDatabase() -> NSURL?{} 

데이터 삽입, 업데이트 및 삭제 방법

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

데이터 선택 방법

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

언급URL : https://stackoverflow.com/questions/24102775/accessing-an-sqlite-database-in-swift

반응형