Acessando um database SQLite no Swift

Eu estou procurando uma maneira de acessar um database SQLite no meu aplicativo com o código Swift.

Eu sei que eu posso usar um Wrapper SQLite no Objective C e usar o header de bridging, mas eu prefiro ser capaz de fazer este projeto inteiramente no Swift. Existe uma maneira de fazer isso, se assim for, alguém pode me apontar para uma referência que mostra como enviar uma consulta, recuperar linhas, etc?

Embora você provavelmente deva usar um dos muitos wrappers do SQLite (prefiro o FMDB , eu mesmo), se você quiser saber como chamar a biblioteca do SQLite você mesmo:

  1. Configure seu projeto Swift para lidar com chamadas SQLite C. Se estiver usando o Xcode 9, você pode simplesmente fazer:

    import SQLite3 

    Nas versões anteriores do Xcode, você pode:

    • Crie um arquivo de header de ponte para o projeto. Veja a seção Importando Objective-C na Swift do Using Swift com Cocoa e Objective-C . Este header de bridging deve importar sqlite3.h :

       #import  
    • Adicione o libsqlite3.tbd (ou para versões mais antigas, o libsqlite3.dylib ) ao seu projeto:

      insira a descrição da imagem aqui

  2. Criar / abrir database

     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. Use sqlite3_exec para executar o SQL (por exemplo, criar tabela).

     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. Use sqlite3_prepare_v2 para preparar o SQL com ? espaço reservado ao qual vamos ligar 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)") } 

    Observe que usa a constante SQLITE_TRANSIENT que pode ser implementada da seguinte maneira:

     internal let SQLITE_STATIC = unsafeBitCast(0, to: sqlite3_destructor_type.self) internal let SQLITE_TRANSIENT = unsafeBitCast(-1, to: sqlite3_destructor_type.self) 
  5. Redefina o SQL para inserir outro valor. Neste exemplo, vou inserir um 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)") } 
  6. Finalize a instrução preparada para recuperar a memory associada a essa instrução preparada:

     if sqlite3_finalize(statement) != SQLITE_OK { let errmsg = String(cString: sqlite3_errmsg(db)!) print("error finalizing prepared statement: \(errmsg)") } statement = nil 
  7. Prepare uma nova instrução para selecionar valores da tabela e loop por meio da recuperação dos 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 
  8. Fechar database:

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

Para o Swift 2, veja a revisão anterior desta resposta .

O melhor que você pode fazer é importar a biblioteca dinâmica dentro de um header de ponte:

  1. Adicione libsqlite3.dylib à sua fase de criação “Vincular Binário com Bibliotecas”
  2. Crie um “Bridging-Header.h” e adicione #import ao topo
  3. set “Bridging-Header.h” para a configuração “Objective-C Bridging Header” em Build Settings sob “Swift Compiler – Code Generation”

Você então poderá acessar todos os methods c como sqlite3_open do seu código rápido.

No entanto, você pode apenas querer usar o FMDB e importá-lo através do header de bridging, já que esse é um wrapper mais orientado a objects do sqlite. Lidar com pointers e estruturas C será complicado em Swift.

Eu também estava procurando por alguma maneira de interagir com o SQLite da mesma forma que eu estava acostumado a fazer anteriormente em Objective-C. É certo que, por causa da compatibilidade C, eu usei apenas a API C reta.

Como nenhum wrapper existe atualmente para o SQLite no Swift e o código SQLiteDB mencionado acima fica um pouco mais alto e assume certo uso, eu decidi criar um wrapper e me familiarizar um pouco com o Swift no processo. Você pode encontrá-lo aqui: 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 */ 

Eu criei uma elegante biblioteca SQLite escrita completamente no Swift chamada SwiftData .

Algumas de suas características são:

  • Vincular objects convenientemente à string de SQL
  • Suporte para transactions e savepoints
  • Manipulação de Erros Inline
  • Completamente thread seguro por padrão

Ele fornece uma maneira fácil de executar ‘alterações’ (por exemplo, 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 } 

e ‘consultas’ (por exemplo, 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)") } } } 

Juntamente com muitos mais resources!

Você pode conferir aqui

Ainda outro wrapper SQLite para Swift 2 e Swift 3: http://github.com/groue/GRDB.swift

Características:

  • Uma API que pareça familiar aos usuários do ccgus / fmdb

  • Uma API de SQLite de baixo nível que aproveita a biblioteca padrão do Swift

  • Uma interface de consulta Swift para desenvolvedores com alergia a SQL

  • Suporte para o modo WAL do SQLite e access simultâneo ao database para desempenho extra

  • Uma class Record que envolve conjuntos de resultados, faz suas consultas SQL personalizadas para o café da manhã e fornece operações CRUD básicas

  • Swift type freedom: escolha o tipo certo de Swift que se ajusta aos seus dados. Use Int64 quando necessário, ou fique com o conveniente Int. Armazene e leia NSDate ou NSDateComponents. Declare enums Swift para tipos de dados discretos. Defina seus próprios tipos de conversíveis em database.

  • Migrações de database

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

AppDelegate.swift

 func createDatabase() { var path:Array=NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true) let directory:String=path[0] let DBpath=(directory as NSString).appendingPathComponent("Food.sqlite") print(DBpath) if (FileManager.default.fileExists(atPath: DBpath)) { print("Successfull database create") } else { let pathfrom:String=(Bundle.main.resourcePath! as NSString).appendingPathComponent("Food.sqlite") var success:Bool do { try FileManager.default.copyItem(atPath: pathfrom, toPath: DBpath) success = true } catch _ { success = false } if !success { print("database not create ") } else { print("Successfull database new create") } } } 

Database.swift

 import UIKit class database: NSObject { func databasePath() -> NSString { var path:Array=NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true) let directory:String=path[0] let DBpath=(directory as NSString).appendingPathComponent("Food.sqlite") if (FileManager.default.fileExists(atPath: DBpath)) { return DBpath as NSString } return DBpath as NSString } func ExecuteQuery(_ str:String) -> Bool { var result:Bool=false let DBpath:String=self.databasePath() as String var db: OpaquePointer? = nil var stmt:OpaquePointer? = nil let strExec=str.cString(using: String.Encoding.utf8) if (sqlite3_open(DBpath, &db)==SQLITE_OK) { if (sqlite3_prepare_v2(db, strExec! , -1, &stmt, nil) == SQLITE_OK) { if (sqlite3_step(stmt) == SQLITE_DONE) { result=true } } sqlite3_finalize(stmt) } sqlite3_close(db) return result } func SelectQuery(_ str:String) -> Array> { var result:Array>=[] 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() 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(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 { var result:Array=[] 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 = "" } 

Banco de dados de access:

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

fogo de consulta do database:

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

Eu escrevi uma biblioteca de wrapper SQLite3 escrita em Swift .

Este é realmente um invólucro de nível muito alto com uma API muito simples, mas, de qualquer forma, ele tem um código intermediário C de baixo nível, e eu posto aqui uma parte (simplificada) dele para mostrar o inter-op.

  struct C { static let NULL = COpaquePointer.null() } func open(filename:String, flags:OpenFlag) { let name2 = filename.cStringUsingEncoding(NSUTF8StringEncoding)! let r = sqlite3_open_v2(name2, &_rawptr, flags.value, UnsafePointer.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, len:Int32, inout zTail:UnsafePointer) -> 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(sql2.UTF8String) var zTail = UnsafePointer.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(cs))! return s1 } func finalize() { let r = sqlite3_finalize(_rawptr) database.checkNoErrorWith(resultCode: r) _rawptr = C.NULL } 

Se você quiser um código-fonte completo desse wrapper de baixo nível, veja esses arquivos.

Configure seu projeto Swift para lidar com chamadas SQLite C:

Crie um arquivo de header de ponte para o projeto. Veja a seção Importando Objective-C na Swift do Using Swift com Cocoa e Objective-C. Este header de bridging deve importar sqlite3.h:

Adicione o libsqlite3.0.dylib ao seu projeto. Veja a documentação da Apple sobre como adicionar biblioteca / estrutura ao projeto.

e usou o seguinte 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(temp))! var keyString = sqlite3_column_name(cStatement,Int32(i)) thisDict.setObject(result, forKey: String.fromCString(UnsafePointer(keyString))!) } result = NSNull() } if result as! NSObject != NSNull() { var keyString = sqlite3_column_name(cStatement,Int32(i)) thisDict.setObject(result, forKey: String.fromCString(UnsafePointer(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 } } } 

Às vezes, uma versão Swift da abordagem “SQLite em 5 minutos ou menos” mostrada no sqlite.org é suficiente. A abordagem “5 minutos ou menos” usa sqlite3_exec() que é um wrapper de conveniência para sqlite3_prepare() , sqlite3_step() , sqlite3_column() e sqlite3_finalize() .

O Swift 2.2 pode suportar diretamente o ponteiro de function de callback sqlite3_exec() como um func procedimento global, sem instância ou um fechamento literal de não captura {} .

typealias legíveis

 typealias sqlite3 = COpaquePointer typealias CCharHandle = UnsafeMutablePointer> typealias CCharPointer = UnsafeMutablePointer typealias CVoidPointer = UnsafeMutablePointer 

Abordagem de retorno de chamada

 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 } 

Abordagem de Fechamento

 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 um projeto Xcode para chamar uma biblioteca C como SQLite, é necessário (1) adicionar headers C de referência do arquivo Bridging-Header.h como #import "sqlite3.h" , (2) adicionar Bridging-Header.h para Objective-C Bridging Header nas configurações do projeto e (3) adicione libsqlite3.tbd às configurações de destino do Link Binary With Library .

O exemplo "SQLite em 5 minutos ou menos" do sqlite.org é implementado em um projeto do Swift Xcode7 aqui .

Você também pode configurar o SQLite com facilidade usando a class de uma única tonelada.

Referir

https://github.com/hasyapanchasara/SQLite_SingleManagerClass

Método para criar database

 func methodToCreateDatabase() -> NSURL?{} 

Método para inserir, atualizar e excluir dados

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

Método para selecionar dados

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

Você pode usar essa biblioteca no Swift para SQLite https://github.com/pmurphyjam/SQLiteDemo

SQLiteDemo

Demonstração SQLite usando Swift com a class SQLDataAccess escrita em Swift

Adicionando ao seu projeto

Você só precisa de três arquivos para adicionar ao seu projeto * SQLDataAccess.swift * DataConstants.swift * Bridging-Header.h Bridging-Header deve ser definido no projeto do Xcode ‘Objective-C Bridging Header’ em ‘Swift Compiler – General’

Exemplos para uso

Basta seguir o código em ViewController.swift para ver como escrever SQL simples com SQLDataAccess.swift Primeiro você precisa abrir o database SQLite seu lidar com

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

Se openConnection for bem-sucedido, agora você pode fazer uma inserção simples no 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)") } ``` 

Veja como isso foi simples!

O primeiro termo em db.executeStatement é seu SQL como String, todos os termos que seguem são uma lista de argumentos variadicos do tipo Any e são seus parâmetros em uma Matriz. Todos esses termos são separados por vírgulas na sua lista de argumentos SQL. Você pode inserir Strings, Integers, Date’s e Blobs logo após a instrução sequel, já que todos esses termos são considerados parâmetros para a sequência. A matriz de argumentos variadicos apenas torna conveniente inserir toda a sua sequela em apenas uma chamada executeStatement ou getRecordsForQuery. Se você não tem nenhum parâmetro, não insira nada após o seu SQL.

A matriz de resultados é uma matriz de dictionary onde a ‘chave’ é o nome da coluna da tabela e o ‘valor’ são os dados obtidos do SQLite. Você pode facilmente percorrer esse array com um loop for ou imprimi-lo diretamente ou atribuir esses elementos Dictionary a Classes de objects de dados personalizados que você usa nos Controladores de exibição para o consumo do modelo.

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

O SQLDataAccess irá armazenar, texto, double, float, blob, Date, integer e long long integers. Para Blobs, você pode armazenar o binário, varbinary, blob.

Para Texto, você pode armazenar caracteres char, character, clob, national varying, character nativo, nchar, nvarchar, varchar, variante, caractere variável, texto.

Para datas, você pode armazenar data e hora, hora, data e hora.

Para Integers, você pode armazenar bigint, bit, booleano, booleano, int2, int8, inteiro, mediumint, smallint, tinyint, int.

Para duplas, você pode armazenar decimal, precisão dupla, flutuação, numérico, real, duplo. O dobro tem mais precisão.

Você pode até armazenar Nulos do tipo Nulo.

No ViewController.swift, um exemplo mais complexo é feito mostrando como inserir um dictionary como um ‘Blob’. Além disso, o SQLDataAccess entende a Data Swift nativa () para que você possa inserir esses objects sem conversão, convertê-los em texto e armazená-los e, quando recuperados, convertê-los de texto para Data.

Claro que o poder real do SQLite é a capacidade de Transação. Aqui você pode literalmente enfileirar 400 instruções SQL com parâmetros e inseri-los todos de uma vez, o que é realmente poderoso, já que é tão rápido. O ViewController.swift também mostra um exemplo de como fazer isso. Tudo o que você realmente está fazendo é criar um Array of Dictionaries chamado ‘sqlAndParams’, neste Array o armazenamento de Dictionaries com duas chaves ‘SQL’ para a instrução sequela String ou query, e ‘PARAMS’ que é apenas um Array de objects nativos SQLite compreende para essa consulta. Cada ‘sqlParams’, que é um dictionary individual de consulta sequel mais parâmetros, é então armazenado no array ‘sqlAndParams’. Depois de criar esse array, basta ligar.

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

Além disso, todos os methods executeStatement e getRecordsForQuery podem ser feitos com uma simples consulta String para SQL e uma Matriz para os parâmetros necessários para a 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)") } ``` 

Uma versão Objective-C também existe e é chamada de mesma SQLDataAccess, então agora você pode escolher escrever sua sequela em Objective-C ou Swift. Além disso, SQLDataAccess também funcionará com SQLCipher, o código atual ainda não está configurado para funcionar, mas é muito fácil de fazer, e um exemplo de como fazer isso está na versão Objective-C do SQLDataAccess.

SQLDataAccess é uma class muito rápida e eficiente, e pode ser usada no lugar do CoreData que realmente usa apenas o SQLite como armazenamento de dados subjacente sem todas as falhas de integridade da integridade dos dados CoreData que vêm com o CoreData.