Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
© 2011-2012 Depto. Ciencia de la Computación e IA
Persistencia
Sesión 3: Persistencia en iOS. Ficheros y SQLite.
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Plataforma iOS © 2011-2012 Depto. Ciencia de la Computación e IA Persistencia: Ficheros y SQLite
Índice de contenidos• Introducción
• Ficheros de propiedades (plist)• Lectura de ficheros• Escritura de ficheros• Personalizar las preferencias de la aplicación
• Base de datos SQLite• Herramientas de gestión de SQLite disponibles.• Lectura de datos.• Escritura de datos.
2
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Plataforma iOS © 2011-2012 Depto. Ciencia de la Computación e IA Persistencia: Ficheros y SQLite
Introducción• Los datos persistentes se almacenan en la memoria flash del
dispositivo.• Los datos almacenados por una aplicación se borrarán del
dispositivo cuando esta se elimine de el.• El SO no permite el acceso a la memoria interna por motivos de
seguridad.• Existen cuatro métodos de persistencia en iOS:• Ficheros PLIST.• Bases de datos SQLite• User Defaults.• Core Data.
• Objetivo: Almacenar datos en nuestra aplicación de la manera más efectiva y sencilla de usar posible.
3
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Plataforma iOS © 2011-2012 Depto. Ciencia de la Computación e IA Persistencia: Ficheros y SQLite
Ficheros de propiedades (1)• Uno de los métodos de persistencia más usados en iOS.• Estructura en árbol -> muy fácil de gestionar y entender.• Internamente es un fichero XML con extensión .plist• Lectura y escritura lenta (acceso a ficheros).• La lectura y escritura no puede hacerse de forma parcial: para
acceder a cualquier dato del fichero deberemos cargarlo completo en memoria -> Poco eficiente.
• Muy útil para modelos muy sencillos de datos y con consultas sencillas:• Base de datos de niveles en un juego.• Propiedades de configuración.• Listados sencillos.
4
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Plataforma iOS © 2011-2012 Depto. Ciencia de la Computación e IA Persistencia: Ficheros y SQLite
Ficheros de propiedades (2)• Ejemplo de fichero plist:
5
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Plataforma iOS © 2011-2012 Depto. Ciencia de la Computación e IA Persistencia: Ficheros y SQLite
Leyendo un fichero plist (1)• Normalmente leeremos el fichero desde el método didFinishLaunchingWithOptions de la clase delegada.
• Después de leerlo almacenaremos en memoria su contenido para evitar tener que acceder en un futuro.
• El fichero plist se encontrará en un principio en el Bundle de la aplicación.
6
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Plataforma iOS © 2011-2012 Depto. Ciencia de la Computación e IA Persistencia: Ficheros y SQLite
Leyendo un fichero plist (2)• Código de lectura del fichero del ejemplo anterior:
7
// Cargamos el fichero PLIST desde el Bundle NSString *mainBundlePath = [[NSBundle mainBundle] bundlePath]; NSString *plistPath = [mainBundlePath stringByAppendingPathComponent:@"configUsuario.plist"]; NSDictionary *diccionario = [[NSDictionary alloc] initWithContentsOfFile:plistPath]; // Cargamos el Diccionario inicial que esta en el raíz del fichero NSDictionary *dicConfig = [diccionario objectForKey:@"config"]; // Cargamos los campos que están dentro del diccionario del raíz NSString *nombre = [dicConfig objectForKey:@"nombre"]; NSString *ciudad = [dicConfig objectForKey:@"ciudad"]; NSArray *dispositivos = [dicConfig objectForKey:@"dispositivos"];
// Mostramos por consola los datos obtenidos NSLog(@"Nombre: %@", nombre); NSLog(@"Ciudad: %@", ciudad); for (NSString *dispositivo in dispositivos){ NSLog(@"Dispositivo: %@", dispositivo); }
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Plataforma iOS © 2011-2012 Depto. Ciencia de la Computación e IA Persistencia: Ficheros y SQLite
Escribiendo en un fichero plist (1)• La escritura se realiza al igual que la lectura accediendo a todo
el fichero, no se puede realizar por partes.• Al igual que en la lectura, se recomienda no acceder
continuamente a la memoria para escribir el fichero ya que esto provocaría un gasto innecesario de recursos y relentizaría la aplicación.
• Antes de comenzar a escribir en un fichero plist, deberemos cargar el fichero en memoria -> Hacer una serie de comprobaciones.
8
¡IMPORTANTE!La escritura sólo funcionará si escribimos en el directorio de documentos del dispositivo, no en el bundle.
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Plataforma iOS © 2011-2012 Depto. Ciencia de la Computación e IA Persistencia: Ficheros y SQLite
Escribiendo en un fichero plist (2)• Carga de un fichero plist en memoria desde el directorio de
documentos.1.Comprobamos si existe la ruta del directorio de documentos. Esta
debería existir, si no, no podremos escribir.2.Comprobamos si estaba ya el fichero plist en el directorio de
documentos.2.1.Si estaba ya simplemente lo cargamos en memoria.2.2.Si no estaba ya, deberemos de copiarlo desde el
bundle al directorio de documentos y de ahí cargarlo en memoria.
9
NSDictionary *diccionarioRaiz; // Ruta del directorio de documentos de nuestro dispositivoNSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); if ([paths count] > 0){ NSString *documentsDirectory = [paths objectAtIndex:0]; NSString *documentsFilename = [documentsDirectory stringByAppendingPathComponent:@"configUsuario.plist"]; // Primero comprobamos si existe el fichero en el directorio de documentos BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:documentsFilename]; if (fileExists) { NSLog(@"Fichero encontrado en directorio de documentos OK: %@!", documentsFilename); // Si existe ya, cargamos los datos desde aqui directamente diccionarioRaiz = [[NSDictionary alloc] initWithContentsOfFile:documentsFilename]; }
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Plataforma iOS © 2011-2012 Depto. Ciencia de la Computación e IA Persistencia: Ficheros y SQLite
Escribiendo en un fichero plist (3)• Código de carga en memoria de un fichero plist desde el
directorio de documentos:
10
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Plataforma iOS © 2011-2012 Depto. Ciencia de la Computación e IA Persistencia: Ficheros y SQLite
Escribiendo en un fichero plist (4)
11
else { NSLog(@"No se encuentra el fichero configUsuario.plist en el directorio de documentos->Lo creamos."); // Si no existe, primero cargamos el fichero PLIST desde el Boundle NSString *mainBundlePath = [[NSBundle mainBundle] bundlePath]; NSString *plistPath = [mainBundlePath stringByAppendingPathComponent:@"configUsuario.plist"]; diccionarioRaiz = [[NSDictionary alloc] initWithContentsOfFile:plistPath]; // Y despues escribimos los datos cargados (el diccionario completo) // a un fichero nuevo de la carpeta de documentos [diccionarioRaiz writeToFile:documentsFilename atomically:YES]; NSLog(@"plist de configUsuario creado!"); }
// Cargamos el Diccionario inicial que esta en el raiz del fichero NSDictionary *dicConfig = [diccionarioRaiz objectForKey:@"config"]; // Cargamos los campos que estan dentro del diccionario del raiz NSString *nombre = [dicConfig objectForKey:@"nombre"]; NSString *ciudad = [dicConfig objectForKey:@"ciudad"]; NSArray *dispositivos = [dicConfig objectForKey:@"dispositivos"]; // Mostramos por consola los datos obtenidos NSLog(@"Nombre: %@", nombre); NSLog(@"Ciudad: %@", ciudad); for (NSString *dispositivo in dispositivos){ NSLog(@"Dispositivo: %@", dispositivo); } // Por ultimo liberamos la memoria del diccionario raiz [diccionarioRaiz release];}
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Plataforma iOS © 2011-2012 Depto. Ciencia de la Computación e IA Persistencia: Ficheros y SQLite
Escribiendo en un fichero plist (5)• Pasos para realizar una escritura en un fichero plist:
1.Comprobamos si existe la ruta de documentos. Esta deberá existir.
2.Cargamos el contenido del fichero en memoria desde el directorio de documentos.
3.Cambiamos, añadimos o borramos los valores que queramos.4.Escribimos los datos que tenemos cargados en memoria en el
fichero.
12
//************************************************** // Cambiamos el nombre y lo guardamos en el fichero // Ruta del directorio de documentos de nuestro dispositivo if ([paths count] > 0) { // Cargamos el fichero desde el directorio de documentos del dispositivo NSString *documentsDirectory = [paths objectAtIndex:0]; NSString *documentsFilename = [documentsDirectory stringByAppendingPathComponent:@"configUsuario.plist"]; diccionarioRaiz = [[NSDictionary alloc] initWithContentsOfFile:documentsFilename]; NSDictionary *dicConfig = [diccionarioRaiz objectForKey:@"config"]; // Cambiamos el valor del nombre en el diccionario [dicConfig setValue:@"Otro nombre" forKey:@"nombre"]; // Escribimos todo el diccionario de nuevo al fichero del // directorio de documentos [diccionarioRaiz writeToFile:documentsFilename atomically:YES]; // Por ultimo liberamos el diccionario de la memoria [diccionarioRaiz release]; }
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Plataforma iOS © 2011-2012 Depto. Ciencia de la Computación e IA Persistencia: Ficheros y SQLite
Escribiendo en un fichero plist (6)• Código de escritura:
13
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Plataforma iOS © 2011-2012 Depto. Ciencia de la Computación e IA Persistencia: Ficheros y SQLite
Preferencias de la aplicación• Podemos personalizar las preferencias de nuestra aplicación
mediante un fichero Settings.• Las preferencias que creemos en el fichero aparecerán dentro
de los ajustes de nuestro dispositivo.• El fichero Settings es de tipo plist en el que cada elemento es
un diccionario (NSDictionary).• Muy útil para configurar variables comunes a toda la aplicación,
como por ejemplo:• Unidades de medida (km, millas...).• Tamaño de letra de los textos.• Mostrar número de versión de la aplicación.• Mostrar información sobre el desarrollador.• Filtros para listados (por ejemplo en aplicaciones de RSS).• etc.
14
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Plataforma iOS © 2011-2012 Depto. Ciencia de la Computación e IA Persistencia: Ficheros y SQLite
Pantalla de preferencias
15
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Plataforma iOS © 2011-2012 Depto. Ciencia de la Computación e IA Persistencia: Ficheros y SQLite
Creando un fichero de preferencias (1)• Seleccionamos: File > New File > Settings > Settings Bundle
16
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Plataforma iOS © 2011-2012 Depto. Ciencia de la Computación e IA Persistencia: Ficheros y SQLite
Creando un fichero de preferencias (2)• Fichero de tipo plist:
17
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Plataforma iOS © 2011-2012 Depto. Ciencia de la Computación e IA Persistencia: Ficheros y SQLite
Creando un fichero de preferencias (3)• Valores permitidos para la propiedad Type:• PSTextFieldSpecifier: Campo de texto.• PSTitleValueSpecifier: Campo título (sólo lectura).• PSToggleSwitchSpecifier: Campo ON/OFF (booleano)• PSSliderSpecifier: Valor númerico en una escala. Tiene
máximo y mínimo.• PSMultiValueSpecifier: Listado de valores entre los que
podemos elegir.• PSGroupSpecifier: Grupo de propiedades.• PSChildPaneSpecifier: Botón que abrirá otra ventana de
propiedades (otro plist).
18
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Plataforma iOS © 2011-2012 Depto. Ciencia de la Computación e IA Persistencia: Ficheros y SQLite
Lectura de valores de preferencias• Los valores de las preferencias se almacenan en la clase NSUserDefaults y podemos acceder a ellos desde cualquier parte de nuestro código:
19
NSString *textValue = [[NSUserDefaults standardUserDefaults]
stringForKey:@”clave_de_la_propiedad”];
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Plataforma iOS © 2011-2012 Depto. Ciencia de la Computación e IA Persistencia: Ficheros y SQLite
SQLite• Base de datos relacional ligera.• Utiliza sentencias SQL para las consultas.• La BD se almacena en un fichero dentro del bundle de la
aplicación.• Rendimiento: algo más rápido que el acceso a ficheros.• Muy útil para modelos de datos algo más complejos.• Uso de librería de c++ -> libsqlite3.dylib • Existe distinto software para la gestión de SQLite totalmente
gratuito. Por ejemplo: SQLite Database Browser.• Muy utilizado antes de la llegada de Core Data a iOS.
20
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Plataforma iOS © 2011-2012 Depto. Ciencia de la Computación e IA Persistencia: Ficheros y SQLite
SQLite Database Browser (1)
21
URL de descarga: http://sourceforge.net/projects/sqlitebrowser/
http://sourceforge.net/projects/sqlitebrowser/http://sourceforge.net/projects/sqlitebrowser/
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Plataforma iOS © 2011-2012 Depto. Ciencia de la Computación e IA Persistencia: Ficheros y SQLite
SQLite Database Browser (2)
22
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Plataforma iOS © 2011-2012 Depto. Ciencia de la Computación e IA Persistencia: Ficheros y SQLite
Lectura de datos en SQLite (1)• Importar la librería libsqlite3.dylib para acceder a la API
de SQLite de Cocoa Touch.• Método para abrir la conexión a la BD: sqlite3_open• Método de para ejecutar una query: sqlite3_prepare_v2• Método para recorrer los resultados: sqlite3_step
• Carga de la base de datos:
23
sqlite3 *_database;
NSString *sqLiteDb = [[NSBundle mainBundle] pathForResource:@"personasDB" ofType:@"sqlite"]; if (sqlite3_open([sqLiteDb UTF8String], &_database) != SQLITE_OK){ NSLog(@"Fallo al abrir la BD!");}
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Plataforma iOS © 2011-2012 Depto. Ciencia de la Computación e IA Persistencia: Ficheros y SQLite
Lectura de datos en SQLite (2)• Código de ejemplo de lectura de datos:
24
NSMutableArray *arraySalida = [[[NSMutableArray alloc] init] autorelease]; NSString *query = @"SELECT id, nombre, apellidos, localidad, edad FROM personas ORDER BY apellidos DESC"; sqlite3_stmt *statement; if (sqlite3_prepare_v2(_database, [query UTF8String], -1, &statement, nil) == SQLITE_OK) { while (sqlite3_step(statement) == SQLITE_ROW) { int uniqueId = sqlite3_column_int(statement, 0); char *nombreChar = (char *) sqlite3_column_text(statement, 1); char *apellidosChar = (char *) sqlite3_column_text(statement, 2); char *localidadChar = (char *) sqlite3_column_text(statement, 3); int edad = sqlite3_column_int(statement, 4); NSString *nombre = [[NSString alloc] initWithUTF8String:nombreChar]; NSString *apellidos = [[NSString alloc] initWithUTF8String:apellidosChar]; NSString *localidad = [[NSString alloc] initWithUTF8String:localidadChar]; Persona *persona = [[Persona alloc] initWithUid:uniqueId nombre:nombre apellidos:apellidos edad:edad localidad:localidad]; [arraySalida addObject:persona]; [nombre release]; [apellidos release]; [localidad release]; [persona release]; } sqlite3_finalize(statement); }
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Plataforma iOS © 2011-2012 Depto. Ciencia de la Computación e IA Persistencia: Ficheros y SQLite
Escritura de datos en SQLite (1)• Se hace el mismo proceso que para leer datos. Sólo
cambiaríamos la sentencia SQL.
• Podremos obtener el último ID insertado mediante el método: ultimoID = sqlite3_last_insert_rowid(database);
25
Especialista Universitario en Desarrollo de Aplicaciones para Dispositivos Móviles
Plataforma iOS © 2011-2012 Depto. Ciencia de la Computación e IA Persistencia: Ficheros y SQLite 26
¿Preguntas?