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.?
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:
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:
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")
}
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)")
}
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_TRANSIENT
qui 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)
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)")
}
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
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
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 .
Le mieux que vous puissiez faire est d'importer la bibliothèque dynamique dans un en-tête de pontage:
#import <sqlite3.h>
en hautVous 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.
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 */
J'ai créé une élégante bibliothèque SQLite entièrement écrite en Swift appelée SwiftData .
Certaines de ses caractéristiques sont:
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
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")
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
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 .
Vous pouvez utiliser cette bibliothèque dans Swift pour SQLite https://github.com/pmurphyjam/SQLiteDemo
Démo SQLite utilisant Swift avec la classe SQLDataAccess écrite en Swift
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".
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.
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.
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
}
}
}
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{}
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.