tabla - Accediendo a una base de datos SQLite en Swift
sqlite swift 4 tutorial (11)
Estoy buscando una forma de acceder a una base de datos SQLite en mi aplicación con el código Swift.
Sé que puedo usar un Contenedor SQLite en Objective C y usar el encabezado puente, pero prefiero poder hacer este proyecto completamente en Swift. ¿Hay alguna manera de hacerlo, si es así, alguien me puede indicar una referencia que muestre cómo enviar una consulta, recuperar filas, etc.?
A veces, una versión Swift del enfoque "SQLite en 5 minutos o menos" que se muestra en sqlite.org es suficiente. El enfoque de "5 minutos o menos" usa sqlite3_exec()
que es un contenedor de conveniencia para sqlite3_prepare()
, sqlite3_step()
, sqlite3_column()
y sqlite3_finalize()
.
Swift 2.2 puede admitir directamente el puntero de función de callback
sqlite3_exec()
como un procedimiento global no func
o un cierre literal no captivo {}
.
typealias
typealias sqlite3 = COpaquePointer
typealias CCharHandle = UnsafeMutablePointer<UnsafeMutablePointer<CChar>>
typealias CCharPointer = UnsafeMutablePointer<CChar>
typealias CVoidPointer = UnsafeMutablePointer<Void>
Enfoque de devolución de llamada
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
}
Enfoque de cierre
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
}
Para preparar un proyecto de Xcode para llamar a una biblioteca de C como SQLite, se necesita (1) agregar un encabezado de referencia C del archivo Bridging-Header.h como #import "sqlite3.h"
, (2) agregar Bridging-Header.h a Objective-C Bridging Header en la configuración del proyecto, y (3) agregue libsqlite3.tbd
al enlace binario con la configuración de destino de la biblioteca .
El sqlite.org "SQLite en 5 minutos o menos" de sqlite.org se implementa aquí en un proyecto de Swift Xcode7.
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
}
}
Modelo.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 datos de acceso:
let DB=database()
var mod=Model()
incendio de Query de base de datos:
var DailyResult:Array<Model> = DB.AllSelectQuery("select * from food where foodtype == ''Sea Food'' ORDER BY name ASC")
Configure su proyecto Swift para manejar llamadas SQLite C:
Crear un archivo de encabezado de puente para el proyecto. Consulte la sección Importar Objective-C en Swift de Using Swift con Cocoa y Objective-C. Este encabezado de puente debería importar sqlite3.h:
Agregue libsqlite3.0.dylib a su proyecto. Consulte la documentación de Apple sobre cómo agregar una biblioteca / marco al proyecto.
y usado el siguiente código
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
}
}
}
Lo mejor que puede hacer es importar la biblioteca dinámica dentro de un encabezado de puente:
- Agregue libsqlite3.dylib a su fase de compilación "Enlace binario con bibliotecas"
- Cree un "Bridging-Header.h" y agregue
#import <sqlite3.h>
a la parte superior - establece "Bridging-Header.h" para el ajuste "Objective-C Bridging Header" en Build Settings en "Swift Compiler - Code Generation"
A continuación, podrá acceder a todos los métodos de c como sqlite3_open
desde su código rápido.
Sin embargo, es posible que desee utilizar FMDB e importarlo a través del encabezado de puente ya que es un contenedor orientado a objetos de sqlite. Tratar con punteros C y estructuras será engorroso en Swift.
Otro contenedor SQLite para Swift 2 y Swift 3: http://github.com/groue/GRDB.swift
caracteristicas:
Una API que resultará familiar para los usuarios de FMDB
Una API SQLite de bajo nivel que aprovecha la biblioteca estándar de Swift
Una bonita interfaz de consulta Swift para desarrolladores alérgicos a SQL
Compatibilidad con el modo SQLite WAL y el acceso simultáneo a la base de datos para un rendimiento adicional
Una clase de registro que envuelve los conjuntos de resultados, come sus consultas SQL personalizadas para el desayuno y proporciona operaciones CRUD básicas
Libertad de tipo swift: elija el tipo Swift adecuado que se ajuste a sus datos. Utilice Int64 cuando sea necesario, o quédese con el conveniente Int. Almacene y lea NSDate o NSDateComponents. Declare enums de Swift para tipos de datos discretos. Defina sus propios tipos de bases de datos convertibles.
Migraciones de base de datos
Velocidad: https://github.com/groue/GRDB.swift/wiki/Performance
Puede usar esta biblioteca en Swift para SQLite https://github.com/pmurphyjam/SQLiteDemo
SQLiteDemo
Demostración de SQLite usando Swift con la clase SQLDataAccess escrita en Swift
Agregando a su proyecto
Solo necesita tres archivos para agregar a su proyecto * SQLDataAccess.swift * DataConstants.swift * Bridging-Header.h Bridging-Header se debe establecer en el proyecto de su Xcode ''Objective-C Bridging Header'' en ''Swift Compiler - General''
Ejemplos de uso
Solo tiene que seguir el código en ViewController.swift para ver cómo escribir SQL simple con SQLDataAccess.swift. Primero necesita abrir la base de datos SQLite que trata con
```swift
let db = SQLDataAccess.shared
db.setDBName(name:"SQLite.db")
let opened = db.openConnection(copyFile:true)
```
Si openConnection tuvo éxito, ahora puede hacer una simple inserción en 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)")
}
```
¡Mira qué simple fue eso!
El primer término en db.executeStatement es su SQL como cadena, todos los términos que siguen son una lista de argumentos variados del tipo Cualquiera, y son sus parámetros en una matriz. Todos estos términos están separados por comas en su lista de argumentos de SQL. Puede ingresar Cadenas, Enteros, Fecha y Blobs justo después de la declaración de la secuela, ya que todos estos términos se consideran parámetros para la continuación. La matriz de argumento variadic simplemente hace que sea conveniente ingresar toda su secuela en una sola llamada executeStatement o getRecordsForQuery. Si no tiene ningún parámetro, no ingrese nada después de su SQL.
La matriz de resultados es una matriz de diccionario donde la ''clave'' es el nombre de la columna de su tabla, y el ''valor'' es la información que obtiene de SQLite. Puede iterar fácilmente a través de esta matriz con un bucle for o imprimirlo directamente o asignar estos elementos de diccionario a clases de objetos de datos personalizados que use en sus controladores de vista para el consumo del modelo.
```swift
for dic in results as! [[String:AnyObject]] {
print(“result = /(dic)”)
}
```
SQLDataAccess almacenará, texto, doble, flotante, blob, fecha, entero y enteros largos. Para Blobs puedes almacenar binary, varbinary, blob.
Para Texto puede almacenar char, carácter, clob, carácter variable nacional, carácter nativo, nchar, nvarchar, varchar, variante, carácter variable, texto.
Para Fechas, puede almacenar fecha y hora, fecha y hora, fecha.
Para enteros puedes almacenar bigint, bit, bool, boolean, int2, int8, entero, mediumint, smallint, tinyint, int.
Para Dobles, puede almacenar decimal, doble precisión, flotante, numérico, real, doble. El doble tiene la mayor precisión.
Incluso puede almacenar nulos de tipo nulo.
En ViewController.swift se realiza un ejemplo más complejo que muestra cómo insertar un diccionario como ''Blob''. Además, SQLDataAccess entiende Swift Date () nativo para que pueda insertar estos objetos sin convertirlos, y los convertirá en texto y los almacenará, y cuando los recupere, los convertirá de texto a Fecha.
Por supuesto, el verdadero poder de SQLite es su capacidad de transacción. Aquí puedes literalmente poner en cola 400 declaraciones SQL con parámetros e insertarlas todas a la vez, lo que es realmente poderoso ya que es muy rápido. ViewController.swift también le muestra un ejemplo de cómo hacer esto. Todo lo que realmente está haciendo es crear una matriz de diccionarios llamada ''sqlAndParams'', en esta matriz, sus diccionarios de almacenamiento con dos claves ''SQL'' para la declaración o consulta de la secuencia Secuencia, y ''PARAMS'' que es simplemente una matriz de objetos nativos SQLite entiende por esa consulta. Cada ''sqlParams'', que es un diccionario individual de consulta secuencial más parámetros, se almacena en la matriz ''sqlAndParams''. Una vez que haya creado esta matriz, simplemente llame.
```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)")
}
```
Además, todos los métodos executeStatement y getRecordsForQuery pueden realizarse con String simple para consulta SQL y una matriz para los parámetros necesarios para la consulta.
```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)")
}
```
También existe una versión de Objective-C que se llama el mismo acceso SQLDataAccess, por lo que ahora puede optar por escribir su secuela en Objective-C o Swift. Además SQLDataAccess también funcionará con SQLCipher, el código actual aún no está configurado para trabajar con él, pero es bastante fácil de hacer, y un ejemplo de cómo hacerlo es en la versión Objective-C de SQLDataAccess.
SQLDataAccess es una clase muy rápida y eficiente, y se puede usar en lugar de CoreData que realmente solo usa SQLite ya que es un almacén de datos subyacente sin todos los fallos de falla de integridad de datos centrales de CoreData que vienen con CoreData.
Si bien debería usar uno de los muchos envoltorios de SQLite (prefiero FMDB , yo mismo), si quisiera saber cómo llamar a la biblioteca SQLite usted mismo, debería:
Configure su proyecto Swift para manejar llamadas SQLite C. Si usa Xcode 9, simplemente puede hacer:
import SQLite3
En versiones anteriores de Xcode, puedes:
Crear un archivo de encabezado de puente para el proyecto. Consulte la sección Importar Objective-C en Swift de Using Swift con Cocoa y Objective-C . Este encabezado de puente debería importar
sqlite3.h
:#import <sqlite3.h>
Agregue
libsqlite3.tbd
(o para versiones aún más antiguas,libsqlite3.dylib
) a su proyecto:
Crear / abrir base de datos.
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") }
Use
sqlite3_exec
para realizar SQL (por ejemplo, crear tabla).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)") }
Use
sqlite3_prepare_v2
para preparar SQL con?
marcador de posición al que enlazaremos el valor.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)") }
Tenga en cuenta que utiliza la constante
SQLITE_TRANSIENT
que se puede implementar de la siguiente manera:internal let SQLITE_STATIC = unsafeBitCast(0, to: sqlite3_destructor_type.self) internal let SQLITE_TRANSIENT = unsafeBitCast(-1, to: sqlite3_destructor_type.self)
Restablece SQL para insertar otro valor. En este ejemplo, insertaré un valor
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)") }
Finalice la instrucción preparada para recuperar la memoria asociada con esa declaración preparada:
if sqlite3_finalize(statement) != SQLITE_OK { let errmsg = String(cString: sqlite3_errmsg(db)!) print("error finalizing prepared statement: /(errmsg)") } statement = nil
Prepare una nueva instrucción para seleccionar valores de la tabla y bucle para recuperar los valores:
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
Cerrar base de datos:
if sqlite3_close(db) != SQLITE_OK { print("error closing database") } db = nil
Para Swift 2, vea la revisión anterior de esta respuesta .
También puede configurar fácilmente SQLite con swift usando una clase de una sola tonelada.
Referir
https://github.com/hasyapanchasara/SQLite_SingleManagerClass
Método para crear una base de datos
func methodToCreateDatabase() -> NSURL?{}
Método para insertar, actualizar y eliminar datos
func methodToInsertUpdateDeleteData(strQuery : String) -> Bool{}
Método para seleccionar datos
func methodToSelectData(strQuery : String) -> NSMutableArray{}
Yo también estaba buscando una forma de interactuar con SQLite de la misma manera en que estaba acostumbrado en Objective-C. Es cierto que, debido a la compatibilidad con C, acabo de utilizar la API C directa.
Como actualmente no existe un contenedor para SQLite en Swift y el código SQLiteDB mencionado anteriormente va un poco más alto y asume cierto uso, decidí crear un contenedor y familiarizarme con Swift en el proceso. Puede encontrarlo aquí: 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 */
Escribí una biblioteca de contenedor SQLite3 escrita en Swift .
En realidad, se trata de un contenedor de muy alto nivel con API muy simple, pero de todos modos, tiene un código interoperativo de C de bajo nivel, y publico aquí una parte (simplificada) de él para mostrar el interoperativo de 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 desea un código fuente completo de este contenedor de bajo nivel, consulte estos archivos.
SwiftData una elegante biblioteca SQLite escrita completamente en Swift llamada SwiftData .
Algunas de sus características son:
- Une objetos convenientemente a la cadena de SQL
- Soporte para transacciones y puntos de rescate
- Manejo de errores en línea
- Completamente seguro de subprocesos por defecto
Proporciona una manera fácil de ejecutar ''cambios'' (por ejemplo, INSERTAR, ACTUALIZAR, ELIMINAR, 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
}
y ''consultas'' (por ejemplo, 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)")
}
}
}
¡Junto con muchas más características!
Puedes verlo SwiftData