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: 5.0/5 (2 votes cast)
VN:F [1.9.8_1114]
Rating: +1 (from 1 vote)
Consulta de bases de datos (sqlite) desde objective-c, 5.0 out of 5 based on 2 ratings

3 Responses to “Consulta de bases de datos (sqlite) desde objective-c”

  1. Diego Diego dice:

    Hola
    Primero gracias por la info, la explicacion linea a linea es perfecta para quienes estamos empezando en esto.

    Quisiera pedirte ayuda en lo siguiente,
    la función “executeSelect” retorna un array de arrays… Como puedo convertir esto a un datasource? o como puedo poner esta info en “UITableView”?.

    Tengo agregado un botón:

    -(IBAction)ManejadorBoton
    {
    //aqui se llama a función -(NSArray *)executeSelect:(NSString *)query
    NSArray *array = [self executeSelect:@"Select * from tabla1"];

    //aqui recorro el resultado de la consulta
    //pero esto quiera meter en una tabla
    for (NSArray *palabra in array) {
    for (NSString *palabra2 in palabra) {
    lbl_primerR.text=palabra2;
    }
    }

    //tbl_registros.dataSource=array;
    }

    saludos y gracias,

    VA:F [1.9.8_1114]
    Rating: 0.0/5 (0 votes cast)
    VA:F [1.9.8_1114]
    Rating: 0 (from 0 votes)
  2. Hola Diego,

    Creo no tienes tan claro el tema de funcionamiento de los UITableViews.
    La propiedad dataSource de la tabla no contiene la información para rellenar la tabla sino indica el objeto con el que puede comunicarse la tabla.
    La conversación entre la tabla y data source puede ser algo parecido a esto:
    Tabla: ¿Hola, yo soy la tabla, cuántas secciones quieres que tenga? (para reguntar eso llama a: – (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView sobre su dataSource).
    DataSource: Quiero que tengas 1 sección (la respuesta iría en el return del método de arriba).

    Tabla: ¿Y cuantas cledas quieres que muestre en esa sección? (usa el método: – (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section=
    DataSource: pués, muestrame 4 celdas (por ejemplo se haría un return [miArrayDeDatos count];).

    Con esto el objeto tableview ya sabé cuánto contenido va a tener.
    Entonces la tabla, por cada celda, pregunta su contenido.

    Tabla: damé la información de la celda de la fila 0 (- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath)
    DataSource: Crea la celda y lo retorna (usando el indexPath.row puede referenciar el contenido de su array de datos).

    El dataSource suele ser el mismo viewController en la que está la tabla (o sea, tabla.dataSource=self).

    Casí mejor que te descargues los ejemplos de uso de tableview desde la página de desarrolladores.
    http://developer.apple.com/library/ios/#samplecode/TableViewSuite/Introduction/Intro.html#//apple_ref/doc/uid/DTS40007318

    Espero que te sirva de algo.
    Un saludo

    VN:F [1.9.8_1114]
    Rating: 0.0/5 (0 votes cast)
    VN:F [1.9.8_1114]
    Rating: +1 (from 1 vote)
  3. Diego Diego dice:

    Hola Aram.

    Muchas gracias. La verdad me sirvio de mucho. Yo lo estaba viendo a este objeto como suelo tratar a los datagrids en .net.

    Muy buena la explicacion “la conversacion entre tabla y dataSource”, me parecio gracioso!! pero muy didactico a la vez.

    gracias nuevamente.

    VA:F [1.9.8_1114]
    Rating: 0.0/5 (0 votes cast)
    VA:F [1.9.8_1114]
    Rating: 0 (from 0 votes)

Leave a Reply

*
preload preload preload