may 09

En este artículo vamos a ver un simple ejemplo de como acceder a una base de datos sqlite desde nuestro código.

Las bases de datos sqlite se usan mucho en las aplicaciones para guardar datos de forma organizada localmente.

Al final del artículo vamos a tener dos funciones creados que podremos reutilizar en nuestros proyectos (el link de descarga abajo de todo).
Entonces, vamos a ver los pasos a seguir para acceder a nuestra base de datos.

Antes de empezar con el código tenemos que añadir la librería de sqlite a nuestro proyecto. Para esto hacemos click con el botón derecho en la carpeta/grupo de frameworks de nuestro proyecto y seleccionamos Add > Existing Frameworks…

Esto nos abrirá una ventana de selección donde tenemos que buscar y seleccionar el framework/librería de sqlite.  Buscamos el libsqlite3.dylib y lo añadimos al nuestro proyecto.

En el fichero donde vayamos a usar las funciones de sqlite para consultar nuestra base de datos tenemos que incluir el sqlite3.h:

#import "sqlite3.h"

Con esto ya estamos preparados para llamar a funciones de la api de sqlite.

La interfaz de acceso a sqlite está hecho en C por lo que podemos acceder a esas funciones sin problemas directamente desde Objective-C. Hay muchas funciones en la api de sqlite que no vamos a usar en los ejemplos de este artículo pero pueden ser indespensables para otros escenarios. Podeís consultar la documentación completa de la api de sqlite aquí.

Vamos a diferenciar dos tipos de consultas: consultas de selección de datos (SELECT) y consultas de modificación (INSERT, UPDATE, DELETE).

IMPORTANTE: no podemos hacer consultas de modificación a la base de datos si está se encuetra entre nuestros ficheros de recursos ya que allí no tenemos permisos de escritura. Para eso lo que se suele hacer es copiar la base de datos desde recursos a la carpeta Documents de nuestra aplicación cuando ejecutamos por primera vez nuestra app.

A continuación vamos a ver un ejemplo de un método que recibe una consulta de selección y nos devuelve un array donde cada elemento de ese array es un registro. Ese registro a su vez es un array donde cada elemento representa a un campo de ese registro. En los comentarios del ejemplo pueden ver las eplicaciones de las funciones usadas:

+(NSArray *)executeSelect:(NSString *)query{
 
	//Declaramos el puntero de la base de datos
	sqlite3 *db;
 
	//Obtenemos el path de nuestra base de datos
	NSString *path = [NSString stringWithFormat:@"%@/Documents/nuestraBaseDeDatos.sqlite", NSHomeDirectory()];
 
	//Intentamos abrir nuestra base de datos
	int r = sqlite3_open([path UTF8String], &db);
 
	if (r != SQLITE_OK){
		NSLog(@"Error al abrir la base de datos");
		return nil;
	}
 
	//sqlite3_stmt representa nuestra consulta
	sqlite3_stmt *statement;
 
	//Creamos nuestro array que contendrá los resultados de nuestra consulta
	NSMutableArray *ar = [[NSMutableArray alloc] initWithCapacity:10];
 
	//Con esta línea se compila la consulta
	if (sqlite3_prepare_v2(db, [query UTF8String], -1, &statement, NULL) == SQLITE_OK) {
		//Obtenemos el número de columnas/campos que van a tener los registros devueltos por nuestra consulta
		int columns = sqlite3_column_count(statement);
 
		//sqlite3_step devuelve un registro, entonces miestras hay registos los
		//añadimos a nuestro array.
		while (sqlite3_step(statement) == SQLITE_ROW) {
			//Declaramos el array donde guardaremos los datos del registro actual
			NSMutableArray *arc = [[NSMutableArray alloc] initWithCapacity:columns];
 
			//Por cada campo del registro obtenido comprobamos si es NULL.
			//Si es nullo añadimos un texto vacio, sino, el texto del regitstro
			for(int i=0; i < columns; i++){
				if (sqlite3_column_text(statement, i) == NULL)
					[arc addObject:@""];
				else
					[arc addObject:[NSString stringWithCString:(char *)sqlite3_column_text(statement, i)
													  encoding:NSUTF8StringEncoding]
					 ];
 
			}
			//Añadimos el registro actual a nuestro array de registros a devolver
			[ar addObject:arc];
			//libermos la memoria del registro actual
			[arc release];
		}
 
	}
	//con esto liberamos la memoria usada por nuestra consulta
	sqlite3_finalize(statement);
 
	//cerramos la base de datos.
	sqlite3_close(db);
 
	[ar autorelease];
 
	return ar;
 
}

Visto el ejemplo de código para una consulta de selección vamos a ver otro de ejemplo para las consultas de modificación que es mucho más simple.

//Sirve para ejecutar comandos sql que no devuelven resultados
+(void)executeQuery:(NSString *)query{
	sqlite3 *db;
 
	NSString *path = [NSString stringWithFormat:@"%@/Documents/miBaseDeDatos.sqlite", NSHomeDirectory()];
 
	int r = sqlite3_open([path UTF8String], &db);
	if (r != SQLITE_OK){
		NSLog(@"Error al abrir la base de datos");
		return;
	}
 
	sqlite3_stmt *statement;
 
	if (sqlite3_prepare_v2(db, [query UTF8String], -1, &statement, NULL) == SQLITE_OK) {
 
		sqlite3_step(statement);
 
	}else{
		NSLog(@"******** Error DB: %@", query);
	}
 
	sqlite3_finalize(statement);
	sqlite3_close(db);
}

Para que estos ejemplos funciones tenéis que poner los paths correctos hacía vuestros bases de datos.
También hay que tener en cuenta que estos métodos no son muy óptimos ya que por cada llamada se ha de conectar a la base de datos y volver a desconectarse, tampoco está muy optimizado la forma de obtener los registros. Pero el código funciona muy bien en escenarios donde no se hace un uso muy intensivo de la base de datos y sirve como un buen ejemplo para empezar con sqlite.
Si no queréis trabajar con la api C de sqlite también se pueden usar los numerosos wrappers que existen para facilitar el acceso a la base de datos. Un de estos que nos gusta es el FMDB.

Descargar ficheros del ejemplo.

VN:F [1.9.8_1114]
Rating: 4.7/5 (3 votes cast)
VN:F [1.9.8_1114]
Rating: +1 (from 1 vote)
Tagged with:
preload preload preload