Estamos hablando de las preferencias por defecto del usuario. En otras palabras, vamos a usar la clase NSUserDefaults, que accede las preferencias que creemos o bien por código o bien con el diseñador de “Settings Bundle”, estas quedan almacenadas en un fichero plist (xml), donde se define cada elemento como un diccionario que contiene los diferentes parámetros en tipos de datos que son diccionarios internamente.
Ejemplo de creación: File -> New File -> Resource -> Settings Bundle.
Normalmente el nombre que se le suele dar al fichero es “Root.plis”, la edición dentro de XCode de este tipo de ficheros de configuración viene a ser algo así:
Estos diccionarios tienen unos tipos de atributos, los siguientes:
Veréis que existen varios tipos de datos a la hora de añadir un diccionario que contiene un elemento de preferencias, estos tipos pueden ser:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; NSString *strUser = [defaults objectForKey:@"usuario"]; int level = [[defaults objectForKey:@"nivel"] intValue]; NSString *strName = [defaults objectForKey:@"nombre"]; NSString *strPass = [defaults objectForKey:@"password"];
Si cargamos la aplicación por primera vez, debemos guardar los valores, igual que antes pero usando la función
[[NSUserDefaults standardUserDefaults] setValue:(id) forKey:(NSString*)];
[NSUserDefaults standardUserDefaults] synchronize]; //imprescindible!
,evidentemente, si los tipos de datos son numéricos, tenemos que encapsularlos en una clase NSNumber, etc.
Para reiniciar los valores en el simulador (esto debemos hacerlo también para cuando cambiemos un fichero traducido de Interface Builder) , borramos el directorio ~/Library/Application Support/iPhone Simulator/User/Applications o bien, abrimos el simulador, y borramos la aplicación o por último, en el menú del simulador – > Restablecer contenidos y ajustes. Esta última opción borrará todas las compilaciones de XIB a NIB (ficheros de I.B.).
Este fichero, según la documentación de XCode, contiene la información de configuración de la aplicación (en un bundle), puede utilizarse para especificar el icono de la aplicación, incluso una cadena “audio” en la variable UIBackgroundModes para cuando la aplicación pasa a segundo plano y estamos haciendo streaming ,que no se corte.
O se puede indicar con la cadena “voip” para que se use un socket para VoIP (luego hace falta que se invoque al método setKeepAliveTimeout: handler para especificar la frecuencia con la que despertar la aplicación para que funcione bien la aplicación, por ejemplo, para cargar el buffer que se está reproduciendo).
Para realizar las traducciones utilizamos dos aplicaciones de XCode que extraen las cadenas de texto a traducir a todos los idiomas: ( ver recursos de traducción> ),
toma como entrada todos los ficheros de implementación y busca NSLocalizedString, creando un fichero codificado con el juego de caracteres UTF-16 con líneas así:
/* Comentario de la llave */
"llave" = "Texto para la llave";
Una vez generados los ficheros para los .m en cada idioma, pues se traducen y luego se deben añadir los directorios al proyecto, si véis que no coge las cadenas de texto, quitad los directorios (en.lproj) sin borrarlos ,sólo la referencia, y luego añadirlos de nuevo
En el fichero strings estarán las cadenas de texto a traducir, una vez hecho, las escribimos de nuevo al .xib:
[sourcecode language="bash"]
ibtool --write MiFichero.strings MiFichero.xib
<< Volver al Curso de Aplicaciones de iOS
|| Ir al siguiente capítulo: Geolocalización con MapKit de Google y CoreLocation »

Guía de uso del Modelo de Datos de iOS:
Podéis ver que el editor trae un soporte para la vista de un bonito Diagrama de Entidad/Relación de nuestra BD.//Crear y configurar una instancia de una entidad Event - (void) createEvent { Event *event = (Event *) [NSEntityDescription insertNewObjectForEntityForName:@"Event" inManagedObjectContext: managedObjectContext]; //Crear un tipo de dato coordenada para mapas de google, así nos acostumbramos a usarlos: CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(37.123123, -3.321321); //Ahora lo tenemos muy fácil ,sólo tenemos que usar los setters & getters generados por XCode: [event setLatitude:[NSNumberWithFloat:coordinate.latitude]]; [event setLongitude:[NSNumberWithFloat:coordinate.longitude]]; [event setCreationDate:[NSDate date]]; //"date" es la fecha de hoy [event setTitle:@"Mi primer evento"]; }
y eso sería todo el código, ahora pasamos a grabar los datos para hacerlos persistentes
NSError *error; if ([managedObjectContext save:&error]){ //prestar especial atención al ampersand...referencia de memoria! //Gestión del error aquí }
Podemos intentar capturar errores con una captura de excepciones (@try { } @catch (NSException *exception) { } @finally { } ) pero esto no es recomendable, además de que debemos recordar la cadena de respondedores, aquí se aplica el mismo cuento y tendríamos que ir hacia arriba en la lógica de la programación para capturar la verdadera excepción de la pila de llamadas…cosa que es bastante tediosa, por eso es mejor pensar las cosas bien y hacerlas mejor jeje, con la práctica todo se consigue ;)
Fetch Request -> execute!

Si queremos recuperar el objeto no tenemos más que usar, como se hace en php y mysql una petición tipo “fetch”, es decir, con NSFetchRequest especificamos la entidad, aquí tenéis un ejemplo completo.
En resumidas cuentas, hay que crear un objeto NSFetchRequest, reutilizamos el objeto de la descripción de una entidad y asociamos esta al primero con setEntity:
NSFetchRequest *request = [[NSFetchRequest alloc] init]; //cuidado que esto no se libera. lo hace sólo...:O NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event" inManagedObjectContext: managedObjectContext]; [request setEntity:entity]; //Para realizar un ORDER BY fecha típico usamos un descriptor de ordenación: NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"creationDate" ascending:NO]; NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil]; [request setSortDescriptors:sortDescriptors]; //ahora sí, liberamos los descriptores [sortDescriptor release]; [sortDescriptors release]; //Con todo configurado, vamos a ejecutar la consulta y guardar el resultado en una matriz modificable: NSError *error1; //Atención al parámetro "mutableCopy"!! NSMutableArray *results = [[managedObjectContext executeFetchRequest:request &error1] mutableCopy]; if ( results == nil ){ //Manejar el error! } //Para borrar necesitamos un NSError igual que cuando guardamos con save NSError *error2; [managedObjectContext deleteObject:objetoEventoParaBorrar]; if (
Recordamos del curso de servicios web que escribir XML y código de un servicio web no es tarea de humanos, para eso existen frameworks que harán el trabajo duro por nosostros, Fremont es la parte cliente, en Objective C, para la parte del servidor tenemos los transformadores que ya vimos, BPEL, etc.
Gracias al uso de un servidor asociado a Google App Engine, crearemos un conjunto de servicios usando Google Web Toolkit 2.3.0 , que una vez probados en red local podremos desplegar en el servidor Java de GAE asociado a nuestra cuenta de usuario.
Pasos para la creación de un servidor de datos por medio de servicios web con Eclipse:

Una vez que hayamos creado nuestras inicializaciones de datos de nuestro modelo (instanciado las clases oportunas), debemos guardarlos usando un gestor de Persistencia, lo que viene a ser una clase de JDOHelper.getPersistenceManagerFactory("transactions-optional"); que por medio de la función makePersistent(clase_instanciada) se almacenará (después debemos hacer un close(), claro jeje)
Como ya hemos visto antes el funcionamiento de la persistencia de datos en iOS con un Modelo de Datos, pasaré directamente al análisis de un XML, aunque esto debería hacerse automáticamente con un framework como Fremont, lo importante es que os quedéis con que las clases que permiten estas tareas son NSURL, NS/Mutable\URLRequest,y NSURLConnection. Estas descargan los datos y podemos realizar el análisis sintáctico con varios tipos de "parser", SAX: envío de notificaciones a medida que el analizador sintáctico va leyendo la cadena XML recibida por NSURL, o bien DOM: es un analizador que lee toda la cadena XML y construye su representación completa. Para utilizar estos analizadores debemos incluir al proyecto el fichero libxml2 de las librerías del SDK (tanto SAX como DOM), o bien NSXMLParser (sólo SAX). Aunque existen alternativas como TBXML, TouchXML, KissXML, TinyXML, GDataXML, etc. --> ver comparativa >>
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:xmlData]; //recibidos por NSURL
[parser setDelegate:self];
A partir de aquí, se trata de usar los eventos del delegado (eventos de NSXMLParserDelegate) que son: didStartElement -> empieza un elemento, didEndelement, didStartDocument, etc. de forma que al principio del documento inicializamos los datos (un array modificable, por ejemplo), y cada vez que encuentra un elemento de tipo titulo pues añade un elemento al array y luego al terminar un elemento de tipo evento, pues añade el array de propiedades de un evento al array de eventos...fácil...Importante implementar también la función:
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError;

La utilización de caché tanto para datos persistentes como para datos dinámicos es importante a la hora de realizar aplicaciones para móviles ya que está muy penalizado el uso de conexiones a Internet, es más rentable llegar a un equilibrio de carga de datos entre el servicio web y los usuarios de los dispositivos, por eso os presento las dos tareas a realizar en un proyecto serio...
En esta dirección encontraréis un framework sorprendente para realizar tareas con análisis sintácticos de XML, descarga de datos a través de urls, caché, etc.
Es una maravilla ver como funcionan los ejemplos, hay uno,especial de caché en el que se dispone una serie de descargas de imágenes y a cada una de ellas se le asocia un puesto en una clase cola-de-espera que tiene asociada una barra de progreso por lo que va actualizando el estado conforme se van descargando los datos...impresionante :)
Lo que podéis hacer es utilizar una caché para guardar la información en un modelo de datos, durante unos días en el iDevice, pasados esos días, vuelve a sincronizarse con el servicio de Google App Engine y reescribimos toda la estructura de datos del programa con nueva información, así nos ahorramos realizar peticiones al servidor continuamente, lo que ralentizaría mucho la carga y si la aplicación es muy usada puede generar un cuello de botella que ha de evitarse.
Para hacer esto nos viene bien los datos de configuración de un usuario, lo veremos en la próxima entrega del curso de aplicaciones para iOS, aquí mismo.
Recordar que podéis utilizar recursos como http://wiki.gnustep.org y http://stackoverflow.com/ para solucionar vuestras dudas tanto con Objective C como con Java Google App Engine y GWT.
En cualquier caso, los ejercicios de esta entrega están claros cuáles son: desplegar una aplicación en GAE con GWT y pasar los datos a un modelo de datos de XCode (SQlite)...hay cientos de tutoriales en internet sin embargo si tenéis cualquier duda, mandadme el fichero y lo intentaré corregir.
<< Volver al curso de programación de aplicaciones de iOS | Siguiente lección: Configuración y traducción de una aplicación de iOS >>