web-dev-qa-db-fra.com

Accéder à une base de données SQLite dans Swift

Je cherche un moyen d'accéder à une base de données SQLite dans mon application avec le code Swift.

Je sais que je peux utiliser un wrapper SQLite dans Objective C et utiliser l'en-tête de pontage, mais je préférerais pouvoir effectuer ce projet entièrement dans Swift. Y a-t-il un moyen de faire cela, si oui, quelqu'un peut-il m'indiquer une référence qui montre comment soumettre une requête, récupérer des lignes, etc.?

90
Jase

Bien que vous deviez probablement utiliser l’un des nombreux wrappers SQLite (je préfère FMDB moi-même), si vous souhaitez savoir comment appeler vous-même la bibliothèque SQLite, vous devez:

  1. Configurez votre projet Swift pour gérer les appels SQLite C. Si vous utilisez Xcode 9, vous pouvez simplement faire:

    import SQLite3
    

    Dans les versions antérieures de Xcode, vous pouvez:

    • Créez un fichier d'en-tête de pontage dans le projet. Reportez-vous à la section Importation d'Objective-C dans Swift de Utilisation de Swift avec cacao et d'Objective-C . Cet en-tête de pontage doit importer sqlite3.h:

      #import <sqlite3.h>
      
    • Ajoutez le libsqlite3.tbd (ou, pour les versions encore plus anciennes, le libsqlite3.dylib) à votre projet:

       enter image description here

  2. Créer/ouvrir une base de données.

    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")
    }
    
  3. Utilisez sqlite3_exec pour exécuter SQL (par exemple, créer une 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. Utilisez sqlite3_prepare_v2 pour préparer le code SQL avec un espace réservé ? auquel nous lierons une valeur.

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

    Notez que cela utilise la constante SQLITE_TRANSIENTqui peut être implémentée comme suit:

    internal let SQLITE_STATIC = unsafeBitCast(0, to: sqlite3_destructor_type.self)
    internal let SQLITE_TRANSIENT = unsafeBitCast(-1, to: sqlite3_destructor_type.self)
    
  5. Réinitialiser SQL pour insérer une autre valeur. Dans cet exemple, je vais insérer une valeur 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. Finalisez l'instruction préparée pour récupérer la mémoire associée à cette instruction préparée:

    if sqlite3_finalize(statement) != SQLITE_OK {
        let errmsg = String(cString: sqlite3_errmsg(db)!)
        print("error finalizing prepared statement: \(errmsg)")
    }
    
    statement = nil
    
  7. Préparez une nouvelle instruction pour sélectionner des valeurs dans une table et effectuez une récupération des valeurs:

    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. Fermer la base de données:

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

Pour Swift 2, voir révision précédente de cette réponse .

123
Rob

Le mieux que vous puissiez faire est d'importer la bibliothèque dynamique dans un en-tête de pontage:

  1. Ajoutez libsqlite3.dylib à votre phase de construction "Link Binary With Libraries"
  2. Créez un "Bridging-Header.h" et ajoutez #import <sqlite3.h> en haut
  3. définissez "Bridging-Header.h" pour le paramètre "En-tête de pontage Objective-C" dans les paramètres de construction sous "Compilateur Swift - Génération de code".

Vous pourrez alors accéder à toutes les méthodes c comme sqlite3_open à partir de votre code Swift.

Cependant, vous voudrez peut-être simplement utiliser FMDB et l’importer via l’en-tête de pontage car c’est un wrapper de sqlite plus orienté objet. Traiter avec les pointeurs et les structures C sera fastidieux à Swift.

15
drewag

Moi aussi, je cherchais un moyen d'interagir avec SQLite comme j'avais l'habitude de le faire auparavant dans Objective-C. Certes, à cause de la compatibilité C, je viens d'utiliser l'API C directe.

Comme aucun emballage n'existe actuellement pour SQLite dans Swift et que le code SQLiteDB mentionné ci-dessus va un peu plus haut et suppose certaines utilisations, j'ai décidé de créer un emballage et de me familiariser un peu avec Swift. Vous pouvez le trouver ici: 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 */
11
Chris Simpson

J'ai créé une élégante bibliothèque SQLite entièrement écrite en Swift appelée SwiftData .

Certaines de ses caractéristiques sont:

  • Lier des objets facilement à la chaîne de code SQL
  • Prise en charge des transactions et des points de sauvegarde
  • Traitement des erreurs en ligne
  • Complètement thread-safe par défaut

Il fournit un moyen simple d’exécuter des «modifications» (par exemple, INSERT, UPDATE, DELETE, etc.):

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
}

et 'requêtes' (par exemple 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)")
        }
    }
}

Avec beaucoup plus de fonctionnalités!

Vous pouvez le vérifier ici

4
ryanfowler

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

Base de données.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 = ""
}

Base de données d'accès:

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

base de données de la requête:

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

Encore une autre enveloppe SQLite pour Swift 2 et Swift 3: http://github.com/groue/GRDB.Swift

Caractéristiques:

  • Une API qui semblera familière aux utilisateurs de ccgus/fmdb

  • API SQLite de bas niveau qui exploite la bibliothèque standard Swift

  • Une jolie interface de requête Swift pour les développeurs SQL-allergiques

  • Prise en charge du mode SQLite WAL et accès simultané à la base de données pour des performances accrues

  • Une classe Record qui encapsule les ensembles de résultats, mange vos requêtes SQL personnalisées pour le petit-déjeuner et fournit des opérations CRUD de base

  • Liberté de type Swift: choisissez le type de Swift adapté à vos données. Utilisez Int64 lorsque vous en avez besoin, ou utilisez la fonction pratique Int. Stockez et lisez NSDate ou NSDateComponents. Déclarez Swift enums pour les types de données discrets. Définissez vos propres types de base de données convertibles.

  • Migrations de bases de données

  • Vitesse: https://github.com/groue/GRDB.Swift/wiki/Performance

2
Gwendal Roué

Parfois, une version Swift de la commande "SQLite en 5 minutes ou moins" affichée sur sqlite.org est suffisante . L'approche "5 minutes ou moins" utilise sqlite3_exec() qui est un wrapper de commodité pour sqlite3_prepare(), sqlite3_step(), sqlite3_column() et sqlite3_finalize().

Swift 2.2 peut directement prendre en charge le pointeur de fonction sqlite3_exec()callback en tant que procédure globale sans instance func ou en tant que fermeture littérale non capturée {}.

Lisible typealias

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

Approche de rappel 

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
}

Approche de fermeture 

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
}

Pour préparer un projet Xcode à appeler une bibliothèque C telle que SQLite, il faut (1) ajouter un en-tête C de référence au fichier Bridging-Header.h tel que #import "sqlite3.h", (2) ajouter Bridging-Header.h à Pontage Objective-C. En-tête dans les paramètres du projet et (3) ajoutez libsqlite3.tbd aux paramètres de la cible Link Binary With Library.

Le sqlite.org 's "L'exemple SQLite en 5 minutes ou moins" est implémenté dans un projet Swift Xcode7 ici .

0
l --marc l

Vous pouvez utiliser cette bibliothèque dans Swift pour SQLite https://github.com/pmurphyjam/SQLiteDemo

SQLiteDemo

Démo SQLite utilisant Swift avec la classe SQLDataAccess écrite en Swift

Ajout à votre projet

Vous n'avez besoin que de trois fichiers à ajouter à votre projet * SQLDataAccess.Swift * DataConstants.Swift * Bridging-Header.h Bridging-Header doit être défini dans le projet "Objective-C Bridging Header" de votre projet Xcode sous "Swift Compiler - General".

Exemples d'utilisation

Il suffit de suivre le code dans ViewController.Swift pour savoir comment écrire du SQL simple avec SQLDataAccess.Swift Vous devez d’abord ouvrir la base de données SQLite avec laquelle vous traitez.

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

Si openConnection a réussi, vous pouvez maintenant effectuer une simple insertion dans la table 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)")
}
```

Voyez comme c'était simple! 

Le premier terme de db.executeStatement est votre SQL en tant que chaîne. Tous les termes qui suivent sont une liste d'arguments variadiques de type Any et constituent vos paramètres dans un tableau. Tous ces termes sont séparés par des virgules dans votre liste d'arguments SQL. Vous pouvez entrer des chaînes, des entiers, des dates et des objets immédiatement après la déclaration de suite, car tous ces termes sont considérés comme des paramètres de la suite. Le tableau d'arguments variadiques facilite simplement la saisie de toute votre suite dans un seul appel executeStatement ou getRecordsForQuery. Si vous n’avez aucun paramètre, n’entrez rien après votre code SQL.

Le tableau de résultats est un tableau de Dictionnaire où la "clé" est le nom de votre colonne de tables et la "valeur" vos données obtenues de SQLite. Vous pouvez facilement parcourir ce tableau avec une boucle for, l'imprimer directement ou attribuer ces éléments de dictionnaire à des classes d'objet de données personnalisées que vous utilisez dans vos contrôleurs de vue pour la consommation de modèle.

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


```

SQLDataAccess stockera, texte, double, float, blob, Date, entier et entier long. Pour les blobs, vous pouvez stocker binaire, varbinary, blob.

Pour le texte, vous pouvez stocker des caractères, des caractères, des caractères, des caractères nationaux différents, des caractères natifs, nchar, nvarchar, varchar, des variantes, des caractères variables, du texte.

Pour les dates, vous pouvez stocker date/heure, heure, horodatage, date.

Pour les nombres entiers, vous pouvez stocker bigint, bit, bool, boolean, int2, int8, entier, mediumint, smallint, tinyint, int.

Pour les doubles, vous pouvez stocker décimal, double précision, float, numérique, réel, double. Double a le plus de précision.

Vous pouvez même stocker des Null de type Null.

Dans ViewController.Swift, un exemple plus complexe montre comment insérer un dictionnaire sous forme de "Blob". De plus, SQLDataAccess Comprend natif Swift Date () de sorte que vous pouvez insérer ces objets sans conversion, ce qui les convertira en texte et les stockera, Et, une fois récupérés, les reconvertira en date.

Bien sûr, le vrai pouvoir de SQLite réside dans sa capacité de transaction. Ici, vous pouvez littéralement mettre en file d'attente jusqu'à 400 instructions SQL avec les paramètres .__ et les insérer toutes en même temps, ce qui est très puissant, du fait de sa rapidité. ViewController.Swift vous montre également un exemple de la procédure à suivre . Tout ce que vous faites est de créer un tableau de dictionnaires appelé 'sqlAndParams', dans ce tableau vos dictionnaires stockés avec deux clés 'SQL' pour l'instruction ou la requête suite à une chaîne, et 'PARAMS' qui est simplement un tableau d'objets natifs que SQLite comprend pour cette requête. Chaque 'sqlParams' qui est un dictionnaire individuel de requête de suite et de paramètres est ensuite stocké dans le tableau 'sqlAndParams'. Une fois que vous avez créé ce tableau, il vous suffit d'appeler.

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

De plus, toutes les méthodes executeStatement et getRecordsForQuery peuvent être réalisées avec une simple chaîne de caractères pour une requête SQL et un tableau pour les paramètres requis par la requête.

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

Une version Objective-C existe également et s'appelle le même SQLDataAccess, vous pouvez donc maintenant choisir d'écrire votre suite dans Objective-C ou Swift . De plus, SQLDataAccess fonctionnera également avec SQLCipher, le code actuel n'est pas encore configuré. pour travailler avec cela, mais c'est assez facile à faire, et un exemple de la façon de le faire est en fait dans la version Objective-C de SQLDataAccess.

SQLDataAccess est une classe très rapide et efficace. Elle peut être utilisée à la place de CoreData, qui utilise uniquement SQLite en tant que données sous-jacentesstore sans toutes les pannes d'erreur d'intégrité des données de base CoreData fournies avec CoreData.

0
Frost

C’est de loin la meilleure bibliothèque SQLite que j’ai utilisée dans Swift: https://github.com/stephencelis/SQLite.Swift

Regardez les exemples de code. Tellement plus propre que l'API C:

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"

La documentation indique également que "SQLite.Swift fonctionne également comme un wrapper léger et convivial pour Swift sur l'API C", suivi de quelques exemples.

0
Andrew Koster

Configurez votre projet Swift pour gérer les appels SQLite C:

Créez un fichier d'en-tête de pontage dans le projet. Reportez-vous à la section Importation d'Objective-C dans Swift de la section Utilisation de Swift avec Cocoa et d'Objective-C. Cet en-tête de pontage doit importer sqlite3.h:

Ajoutez le fichier libsqlite3.0.dylib à votre projet. Voir la documentation d'Apple concernant l'ajout d'une bibliothèque/d'un framework à son projet.

et utilisé le code suivant

    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
chirag shah

Vous pouvez aussi facilement configurer SQLite avec Swift en utilisant une classe de tonne unique.

Référer

https://github.com/hasyapanchasara/SQLite_SingleManagerClass

Méthode pour créer une base de données

func methodToCreateDatabase() -> NSURL?{} 

Méthode pour insérer, mettre à jour et supprimer des données

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

Méthode de sélection des données

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

J'ai écrit une bibliothèque d'encapsulation SQLite3 écrite en Swift

C’est en fait un wrapper de très haut niveau avec une API très simple, mais de toute façon, il a un code C inter-op de bas niveau, et je publie ici une partie (simplifiée) de celle-ci pour montrer l’inter-op 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
    }

Si vous voulez un code source complet de ce wrapper de bas niveau, consultez ces fichiers.

0
Eonil