Swift'de bir SQLite Veritabanına Erişme


103

Swift koduyla uygulamamda bir SQLite veritabanına erişmenin bir yolunu arıyorum.

Objective C'de bir SQLite Wrapper kullanabileceğimi ve köprüleme başlığını kullanabileceğimi biliyorum, ancak bu projeyi tamamen Swift ile yapmayı tercih ederim. Bunu yapmanın bir yolu var mı, eğer öyleyse, birisi beni sorgu göndermeyi, satırları almayı vb. Gösteren bir referansa yönlendirebilir mi?



1
veritabanı dosyamı nereye koymalıyım?
C. Feliana

1
@ C.Feliana - Uygulama destek dizini harika bir yer, örn let dbPath = try! FileManager.default.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true).appendingPathComponent("test.sqlite").path.
Rob

Yanıtlar:


144

Muhtemelen birçok SQLite sarmalayıcısından birini kullanmanız gerekse de, SQLite kitaplığını kendiniz nasıl arayacağınızı öğrenmek istiyorsanız, şunları yaparsınız:

  1. Swift projenizi SQLite C çağrılarını işleyecek şekilde yapılandırın. Xcode 9 veya sonraki bir sürümünü kullanıyorsanız, şunları yapabilirsiniz:

    import SQLite3
  2. Veritabanı oluşturun / açın.

    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
    }

    Not, açılmadığında veritabanını kapatmanın garip göründüğünü biliyorum, ancak sqlite3_open belgeler bellek sızıntısını önlemek için bunu yapmamız gerektiğini açıkça belirtiyor:

    Açıldığında bir hata oluşsun ya da oluşmasın, veritabanı bağlantı tutamacıyla ilişkili kaynaklar sqlite3_close()artık gerekli olmadığında iletilerek serbest bırakılmalıdır .

  3. sqlite3_execSQL gerçekleştirmek için kullanın (örneğin, tablo oluşturun).

    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. Değeri bağlayacağımız yer tutucu sqlite3_prepare_v2ile SQL hazırlamak için kullanın ?.

    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)")
    }

    Aşağıdaki gibi uygulanabilenSQLITE_TRANSIENT sabiti kullandığına dikkat edin :

    internal let SQLITE_STATIC = unsafeBitCast(0, to: sqlite3_destructor_type.self)
    internal let SQLITE_TRANSIENT = unsafeBitCast(-1, to: sqlite3_destructor_type.self)
  5. Başka bir değer eklemek için SQL'i sıfırlayın. Bu örnekte bir NULLdeğer ekleyeceğim :

    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. Hazırlanan ifadeyle ilişkili hafızayı kurtarmak için hazırlanan ifadeyi sonlandırın:

    if sqlite3_finalize(statement) != SQLITE_OK {
        let errmsg = String(cString: sqlite3_errmsg(db)!)
        print("error finalizing prepared statement: \(errmsg)")
    }
    
    statement = nil
  7. Tablodan değer seçmek için yeni bir ifade hazırlayın ve değerleri almak için döngü yapın:

    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. Veritabanını kapat:

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

Swift 2 ve Xcode'un daha eski sürümleri için , bu cevabın önceki revizyonlarına bakın .


1
1. geçişte bazı sorunlar yaşayanlar için şunu göz önünde bulundurun: Xcode projenizde bir Köprü Başlığı oluşturun (ör. BridgingHeader.h); Bu başlık dosyası, Swift'e köprü oluşturmak için yalnızca Objective-C / C başlıklarını içe aktaran satırlara sahip olabilir (örn. #İnclude <sqlite3.h>); "Yapı Ayarları" üzerinde "Objective-C Bridging Header" ı bulun (arama çubuğunu kullanabilirsiniz) ve "BridgingHeader.h" yazın ("Objective-C Header içe aktarılamadı" gibi bir hata mesajı alırsanız, deneyin "proje- name / BridgingHeader.h "); "Aşamaları Oluştur", "Kitaplıklarla İkili Bağlantı Kur" seçeneğine gidin ve XCode 7
Jorg B Jorge

Eğer başarısız olursa aşağıdakilerin çalıştırılmaması için if (... == SQLITE_OK) 'u iç içe yerleştirmek daha iyi olur mu? Sadece soruyorum çünkü bu konuda çok yeniyim ve bunu öğretme amacıyla yaptıysan merak ettim.
quemeful

@quemeful - Elbette, ancak bunu birçok SQLite çağrısıyla yaparsanız, gerçekten derinlemesine iç içe geçmiş bir kod elde edersiniz. Bu konuda endişeleniyorsan, muhtemelen guardbunun yerine ifadeler kullanırım.
Rob

@Jorg B Jorge Her şeyi yaptım, ayrıca bir şekilde köprüleme başlığını içe aktarmanız gerekiyor mu? Test sınıfında çalışıyorum
Async

Merhaba @ Rob, burada bir Swift projesinde sqlite sarmalayıcınızı kullanıyorum. Gerçekten güzel, teşekkürler. Ancak, onunla tablodan seçme sayımı (*) yapamıyorum. Sürekli çöküyor. Tablename'den some_col = xxx olan bir seçme sayımı (col_name) yaptıysam, çalışıyor. Sen ne önerirsin?
gbenroscience

18

Yapabileceğiniz en iyi şey, dinamik kitaplığı bir köprüleme başlığının içine aktarmaktır:

  1. Libsqlite3.dylib'i "Kitaplıklarla İkili Bağlantı Kur" oluşturma aşamasına ekleyin
  2. Bir "Bridging-Header.h" oluşturun ve #import <sqlite3.h>en üste ekleyin
  3. "Swift Compiler - Kod Oluşturma" altındaki Yapı Ayarlarında "Objective-C Köprüleme Başlığı" ayarı için "Bridging-Header.h" öğesini ayarlayın

Daha sonra sqlite3_open, swift kodunuzdaki gibi tüm c yöntemlerine erişebileceksiniz .

Ancak, FMDB'yi kullanmak ve bunu köprüleme başlığı aracılığıyla içe aktarmak isteyebilirsiniz, çünkü bu daha nesne yönelimli bir sqlite sarmalıdır. Swift'de C işaretçileri ve yapıları ile uğraşmak külfetli olacaktır.


Xcode'un köprüleme başlığını bulması için bunu Proje oluşturma ayarları altında eklemem gerekiyordu, Hedef oluşturma ayarları değil.
rob5408

3
ayrıca herkes ve babası şimdi bir Swift ambalajı yarattı .. aşağıya bakın
quemeful

1
Ne yazık ki hiçbiri aşırı derecede olgun değil, bu yüzden bu yeni paketleyicilerden herhangi birini kullanırsanız dikkatli olun. Örneğin, yazı yazarken, dördüne baktım ve üç tarihi yanlış ele aldı ve dördüncüsü hiç işlemedi.
Rob

Baktığınız mı @Rob github.com/stephencelis/SQLite.swift#readme ? NSDate ile kullanmak üzere yapılandırma hakkında bilgi burada: github.com/stephencelis/SQLite.swift/blob/master/Documentation/…
stephencelis

@stephencelis Hey, bu çoğundan daha iyi, çünkü en azından saat dilimini belirliyorsunuz, ama yine de bununla ilgili sorunlarım var NSDateFormatter. Ancak niyetim, bu belirli uygulamaların bu özel yönünü eleştirmekten ziyade, bunun daha geniş bir sorunun göstergesi olduğunu, FMDB gibi çözümlerin sahip olduğu iyileştirme yıllarına sahip olmadıklarını öne sürmekti. Bence insanlar, kanıtlanmış Objective-C çözümlerini daha az olgun Swift uygulamaları lehine atmakta çok hızlılar (TFHpple vs NDHpple başka bir iyi örnek).
Rob

11

Ben de daha önce Objective-C'de kullandığım gibi SQLite ile etkileşim kurmanın bir yolunu arıyordum. Kuşkusuz, C uyumluluğu nedeniyle, sadece düz C API kullandım.

Swift'de SQLite için şu anda bir sarmalayıcı bulunmadığından ve yukarıda bahsedilen SQLiteDB kodu biraz daha yüksek seviyeye gittiğinden ve belirli bir kullanım olduğunu varsaydığından, bir sarmalayıcı oluşturmaya ve bu süreçte Swift'e biraz aşina olmaya karar verdim. Onu burada bulabilirsiniz: 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 */

5

SwiftData adında tamamen Swift ile yazılmış zarif bir SQLite kitaplığı oluşturdum .

Bazı özellikleri şunlardır:

  • Nesneleri SQL dizesine uygun şekilde bağlayın
  • İşlemler ve kayıt noktaları için destek
  • Satır içi hata işleme
  • Varsayılan olarak tamamen iş parçacığı güvenli

'Değişiklikleri' yürütmek için kolay bir yol sağlar (örn. INSERT, UPDATE, DELETE, vb.):

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
}

ve 'sorgular' (örneğin SEÇ):

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)")
        }
    }
}

Daha birçok özellikle birlikte!

Buradan kontrol edebilirsiniz


Maalesef kitaplığınız yalnızca iOS içindir! : - /
BadmintonCat

3

Swift 2 ve Swift 3 için başka bir SQLite sarmalayıcı: http://github.com/groue/GRDB.swift

Özellikleri:

  • Ccgus / fmdb kullanıcılarına tanıdık gelecek bir API

  • Swift standart kitaplığından yararlanan düşük seviyeli bir SQLite API

  • SQL alerjisi geliştiriciler için hoş bir hızlı sorgu arayüzü

  • SQLite WAL modu desteği ve ekstra performans için eşzamanlı veritabanı erişimi

  • Sonuç kümelerini saran, özel SQL sorgularınızı kahvaltıda yiyen ve temel CRUD işlemlerini sağlayan bir Record sınıfı

  • Hızlı yazma özgürlüğü: Verilerinize uyan doğru Swift türünü seçin. Gerektiğinde Int64 kullanın veya uygun Int ile devam edin. NSDate veya NSDateComponents'ı saklayın ve okuyun. Ayrık veri türleri için Swift numaralandırmalarını bildirin. Kendi veritabanı dönüştürülebilir türlerinizi tanımlayın.

  • Veritabanı Taşıma İşlemleri

  • Hız: https://github.com/groue/GRDB.swift/wiki/Performance


GRDB, Github'daki en iyi belgelenmiş, desteklenen ve bakımı yapılan çerçevelerden biridir!
Klaas

3

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 = ""
}

Erişim veritabanı:

let DB=database()
var mod=Model()

veritabanı Sorgu ateşi:

var DailyResult:Array<Model> = DB.AllSelectQuery("select * from food where foodtype == 'Sea Food' ORDER BY name ASC")

bu qyery çalışmıyor. neden tek bir = yerine == var?
ArgaPK

1

Bu, Swift'de kullandığım en iyi SQLite kitaplığı: https://github.com/stephencelis/SQLite.swift

Kod örneklerine bakın. C API'den çok daha temiz:

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"

Belgeler ayrıca "SQLite.swift'in aynı zamanda C API üzerinden hafif, Swift dostu bir sarmalayıcı olarak çalıştığını" söylüyor ve bunun bazı örnekleri ile devam ediyor.


0

Swift ile yazılmış bir SQLite3 sarıcı kitaplığı yazdım .

Bu aslında çok basit bir API ile çok yüksek seviyeli bir sarmalayıcıdır, ancak yine de, düşük seviyeli C operasyonlar arası koduna sahiptir ve burada C operasyonlarını göstermek için (basitleştirilmiş) bir bölümünü gönderiyorum.

    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
    }

Bu düşük seviyeli sarmalayıcının tam kaynak kodunu istiyorsanız, bu dosyalara bakın.


0

Swift projenizi SQLite C çağrılarını işleyecek şekilde yapılandırın:

Projeye köprü başlık dosyası oluşturun. Swift'i Cocoa ve Objective-C ile Kullanma'nın Objective-C'yi Swift'e Aktarma bölümüne bakın. Bu köprüleme başlığı sqlite3.h dosyasını içe aktarmalıdır:

Libsqlite3.0.dylib'i projenize ekleyin. Birinin projesine kitaplık / çerçeve eklemeyle ilgili Apple belgelerine bakın.

ve aşağıdaki kodu kullandı

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

0

Bazen, sqlite.org'da gösterilen "5 dakika veya daha kısa sürede SQLite" yaklaşımının bir Swift versiyonu yeterlidir. "5 dakika ya da daha az" yaklaşımı kullanır için kullanışlı bir sarıcı , , ve .sqlite3_exec()sqlite3_prepare()sqlite3_step()sqlite3_column()sqlite3_finalize()

Swift 2.2, sqlite3_exec() callbackişlev işaretçisini global, örnek olmayan prosedür funcveya yakalamayan değişmez kapanış olarak doğrudan destekleyebilir {}.

Okunabilir typealias

typealias sqlite3 = COpaquePointer
typealias CCharHandle = UnsafeMutablePointer<UnsafeMutablePointer<CChar>>
typealias CCharPointer = UnsafeMutablePointer<CChar>
typealias CVoidPointer = UnsafeMutablePointer<Void>

Geri Arama Yaklaşımı

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
}

Kapatma Yaklaşımı

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
}

Örneğin SQLite'ta gibi bir C kütüphanesi aramak için bir Xcode proje hazırlamak için, (1) başlıkları gibi bir köprü-Header.h dosya referans C eklemek için bir ihtiyaç #import "sqlite3.h", (2), Köprü-Header.h ilave amaç-Cı Köprüleme üstbilgi projesinde ayarları ve (3) eklemek libsqlite3.tbdiçin bağlantı İkili ile Kütüphane hedef ayarları.

Sqlite.org 'ın 'SQLite 5 dakika veya daha az' Örneğin bir Swift Xcode7 projede uygulanmaktadır burada .


0

Bu kitaplığı Swift için SQLite https://github.com/pmurphyjam/SQLiteDemo için kullanabilirsiniz

SQLiteDemo

Swift ile Swift ile yazılmış SQLDataAccess sınıfını kullanan SQLite Demosu

Projenize Eklemek

Projenize eklemek için yalnızca üç dosyaya ihtiyacınız var * SQLDataAccess.swift * DataConstants.swift * Bridging-Header.h Bridging-Header, Xcode projenizin 'Swift Compiler - Genel' altında 'Objective-C Bridging Header' içinde ayarlanmalıdır

Kullanım Örnekleri

SQLDataAccess.swift ile nasıl basit SQL yazılacağını görmek için ViewController.swift'teki kodu takip etmeniz yeterli.Öncelikle uğraştığınız SQLite Veritabanını açmanız gerekir.

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

OpenConnection başarılı olduysa, şimdi Table AppInfo'ya basit bir ekleme yapabilirsiniz.

    //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)")
    }

Bunun ne kadar basit olduğunu görün!

Db.executeStatement içindeki ilk terim, String olarak SQL'inizdir, takip eden tüm terimler Any türünde değişken bir argüman listesidir ve bir Array'deki parametrelerinizdir. Tüm bu terimler, SQL argümanları listenizde virgülle ayrılır. Dizeler, Tamsayılar, Tarihler ve Bloblar sekans ifadesinden hemen sonra girebilirsiniz çünkü bu terimlerin tümü, devam filmi için parametreler olarak kabul edilir. Variadic argüman dizisi sadece bir executeStatement veya getRecordsForQuery çağrısında tüm devam dizinizi girmenizi kolaylaştırır. Herhangi bir parametreniz yoksa, SQL'inizden sonra hiçbir şey girmeyin.

Sonuçlar dizisi bir Sözlük Dizisidir ve burada 'anahtar' tablolar sütun adınızdır ve 'değer' ise SQLite'den elde edilen verilerinizdir. Bu diziyi bir for döngüsü ile kolayca yineleyebilir veya doğrudan yazdırabilir veya bu Sözlük öğelerini, model tüketimi için Görünüm Denetleyicilerinizde kullandığınız özel veri nesnesi Sınıflarına atayabilirsiniz.

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

SQLDataAccess, text, double, float, blob, Date, integer ve long long tamsayıları depolar. Bloblar için ikili, varbinary, blob depolayabilirsiniz.

Metin için karakter, karakter, clob, ulusal değişen karakter, yerel karakter, nchar, nvarchar, varchar, varyant, değişken karakter, metin depolayabilirsiniz.

Tarihler için tarih saat, saat, zaman damgası, tarih saklayabilirsiniz.

Tamsayılar için bigint, bit, bool, boolean, int2, int8, integer, mediumint, smallint, tinyint, int depolayabilirsiniz.

Çiftler için ondalık, çift duyarlıklı, kayan, sayısal, gerçek, çift depolayabilirsiniz. Double en yüksek hassasiyete sahiptir.

Null türündeki Null'ları bile depolayabilirsiniz.

ViewController.swift'te, Sözlüğün 'Blob' olarak nasıl ekleneceğini gösteren daha karmaşık bir örnek yapılmıştır. Buna ek olarak, SQLDataAccess yerel Swift Date () 'i anlar, böylece bu nesneleri dönüştürme yapmadan ekleyebilirsiniz ve bunları metne dönüştürüp saklayacak ve geri alındığında bunları metinden Tarihe geri dönüştürecektir.

Tabii ki SQLite'ın gerçek gücü Transaction yeteneğidir. Burada tam anlamıyla parametrelerle 400 SQL ifadesini sıralayabilir ve hepsini bir kerede ekleyebilirsiniz, bu çok hızlı olduğu için gerçekten güçlüdür. ViewController.swift ayrıca bunun nasıl yapılacağına dair bir örnek gösterir. Gerçekten yaptığınız tek şey, 'sqlAndParams' adlı bir Sözlükler Dizisi oluşturmaktır, bu Dizide, String sekans ifadesi veya sorgusu için iki anahtar 'SQL' ve yalnızca yerel nesnelerden oluşan bir Dizi olan 'PARAMS' ile Sözlükleri depolamaktır. o sorgu için anlar. Ardışık sorgu artı parametrelerinin ayrı bir Sözlüğü olan her 'sqlParams' daha sonra 'sqlAndParams' Dizisinde saklanır. Bu diziyi oluşturduğunuzda, sadece arayın.

    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)")
    }

Ek olarak, tüm executeStatement ve getRecordsForQuery yöntemleri SQL sorgusu için basit String ve sorgu tarafından ihtiyaç duyulan parametreler için bir Array ile yapılabilir.

    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)")
    }

Bir Objective-C sürümü de mevcuttur ve aynı SQLDataAccess olarak adlandırılır, bu nedenle artık devam filminizi Objective-C veya Swift ile yazmayı seçebilirsiniz. Buna ek olarak SQLDataAccess, SQLCipher ile de çalışacaktır, mevcut kod henüz onunla çalışmak için kurulmamıştır, ancak yapılması oldukça kolaydır ve bunun nasıl yapılacağına dair bir örnek aslında SQLDataAccess'in Objective-C sürümündedir.

SQLDataAccess çok hızlı ve verimli bir sınıftır ve CoreData ile birlikte gelen tüm CoreData çekirdek veri bütünlüğü hatası çökmeleri olmadan temel veri deposu olduğu için gerçekten sadece SQLite kullanan CoreData yerine kullanılabilir.


-1

Tek ton sınıfını kullanarak SQLite'ı swift ile kolaylıkla yapılandırabilirsiniz.

Öner

https://github.com/hasyapanchasara/SQLite_SingleManagerClass

Veritabanı oluşturma yöntemi

func methodToCreateDatabase() -> NSURL?{} 

Veri ekleme, güncelleme ve silme yöntemi

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

Veri seçme yöntemi

func methodToSelectData(strQuery : String) -> NSMutableArray{}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.