Mandando SMS o Correos desde nuestra App

julio 20, 2011

Seguramente en muchas ocasiones se nos habrá presentado la necesidad de mandar información desde nuestra aplicación al “exterior”. Para mandar esa información tenemos varias alternativas, sin duda una de las mas sencillas es utilizar los propios mecanismos del móvil para hacerlo. Estos mecanismos son básicamente dos, mandar un correo electrónico o mandar un mensaje corto.

iOS nos proporciona un framework para realizar esta tareas, el nombre es Message UI. Este framework, nos va a proporcionar ViewControllers que podremos invocar desde nuestra aplicación y de esta manera, enviar el mensaje de correo o SMS sin tener que abandonarla.

Junto con los ViewControllers, el framework proporciona dos protocolos que representan los delegados de dichos controladores, de tal manera que podemos recibir información de como ha sido el proceso de envío.

Las clases de los controladores son MFMailComposeViewController y MFMessageComposeViewController.

Antes de empezar a experimentar con las clases, es importante que añadamos el framework a nuestro proyecto, ya que por defecto no lo tendremos. Para ello lo hacemos desde la siguiente ventana de XCode.

Empezando por la del correo electrónico, la clase nos proporciona diversos métodos para prefijar los contenidos, como “setSubject:” “setToRecipients:” o “setMessageBody:isHTML:”. Pese a que al ser un viewcontroller cualquiera, podemos usar cualquier técnica para mostrarlo, se recomienda usar el mensaje “presentModalViewController:animated:” de UIViewController.

Es importante notar que una vez que el controlador esta en primer plano, nuestra aplicación no puede cambiar el contenido del correo. Esto es así para prevenir aplicaciones “maliciosas” que podrían mostrar una cosa y luego enviar otra.

De esta manera el código para mostrar la pantalla de envío de correo seria:

MFMailComposeViewController *mailcontroller = [[MFMailComposeViewController alloc] init];
[mailcontroller setSubject:subjectText.text];
[mailcontroller setMessageBody:bodyText.text isHTML:NO];
mailcontroller.mailComposeDelegate = self;
[self presentModalViewController:mailcontroller animated:YES];

Como vemos en el código, previamente tenemos que establecer una instancia como delegado del controlador, cuando el usuario interactue con el controlador, se nos enviara un mensaje del tipo: “mailComposeController:didFinishWithResult:error:”. Este paso es importante pues nosotros somos los encargados de ocultar el viewcontroller cuando el usuario haya acabado, y esto lo hacemos llamando a “dismissModalViewControllerAnimated:” en el código del delegado.

- (void)mailComposeController:(MFMailComposeViewController *)controller
          didFinishWithResult:(MFMailComposeResult)result
                        error:(NSError *)error
{
    [controller dismissModalViewControllerAnimated:YES];
}

El caso del controlador de mensajes cortos es muy similar al del correo. La clase es MFMessageComposeViewController, y las propiedades que controlan el contenido son “recipients” y “body”, de la misma manera el controlador se muestra con el mensaje “presetModalViewController:animated” y el delegado, en este caso una clase que implemente el protocolo “MFMessageComposeViewControllerDelegate” y el método “messageComposeViewController:didFinishWithResult:” deberá ocultar el controlador una vez que el mensaje haya sido enviado.

MFMessageComposeViewController *smscontroller = [[MFMessageComposeViewController alloc] init];
smscontroller.body = bodyText.text;
smscontroller.messageComposeDelegate = self;
[self presentModalViewController:smscontroller animated:YES];

...

- (void)messageComposeViewController:(MFMessageComposeViewController *)controller
                 didFinishWithResult:(MessageComposeResult)result
{
    [controller dismissModalViewControllerAnimated:YES];
}

Ambos controladores poseen un mensaje estático que nos permite comprobar la disponibilidad de estos métodos. Dichos mensajes son “canSendText” y “canSendMail”. Así si estamos en un iPod Touch sin posibilidad de enviar SMS, podemos comprobarlo antes de intentar utilizar esta funcionalidad.

Como veis, el mecanismo para realizar este tipo de tareas es bastante sencillo a la vez que útil.

Anuncios

Barras de búsqueda en iOS

junio 12, 2011

Seguramente en muchas de nuestras aplicaciones de iOS hemos tenido que mostrar una tabla de datos con un montón de entradas. Desde el punto de vista del usuario, es bastante molesto tener que buscar el elemento que quiere entre todos los elementos.

Para mejorar la usabilidad, se plantean varias alternativas. Podemos separar los datos en varios niveles, de tal manera que dividamos los datos en varios bloques, sin embargo, esta solución tiene como inconveniente que obligamos a navegar por varias pantallas.

Concretamente en iOS tenemos varias alternativas para “ordenar” nuestros datos a nivel visual. Podemos crear listas por secciones e incluso incluir un indice para saltar entre los diferentes datos al mas puro estilo iTunes o la aplicación que muestra los Contactos.

Sin embargo, aunque ayuda, no acaba de solucionar el problema de tener que buscar la entrada que queremos en nuestra tabla.

Aquí es donde entra el campo de búsqueda que seguro habéis visto en numerosas aplicaciones de iOS como Facebook, Twitter o iTunes. En esta entrada vamos a ver como añadir una barra de búsqueda a nuestra aplicación.

Dentro del conjunto de controles estándar de iOS, tenemos la clase UISearchBar, que representa el cuadro de texto con esquinas redondeadas y la lupa a la que estamos acostumbrados. Sin embargo, este elemento es solo la parte gráfica del sistema de búsqueda. Además de esta clase, vamos a necesitar tratar con la clase UISearchDisplayController, que será la que enlazada a los ViewControllers habituales, nos van a proporcionar todo el sistema de búsqueda que hemos visto en las aplicaciones antes comentadas.

Esta instancia de UISearchDisplayController no vive sola, la mayoría de nuestras vistas, están gestionadas por una clase “Controller” que hereda de UIViewController, en esta clase esta definida una propiedad llamada searchDisplayController, a la que podemos asignar nuestra clase controladora del campo de búsqueda. Haciendo esto ganamos bastante funcionalidad.

Si hemos visto el funcionamiento de la barra de búsqueda, hemos visto como al tocar para introducir texto, esta barra se coloca en la parte superior de forma animada, sombreando además la vista entera, además, en algunos casos salen unos botones debajo de la barra de búsqueda, que indican donde se esta realizando la búsqueda. Pues bien, todo este comportamiento esta “de propina” si asignamos la propiedad del ViewController a nuestro SearchController.

Para llevar esto a la práctica, suponiendo que tenemos un proyecto con un NavigationController, tenemos que ir a la vista que se carga como contenido del navigation controller y añadir el SearchViewController.

Automáticamente XCode asigna los outlets, pero para saber como funciona, no es mala idea cotillearlos un poco. XCode establece el outlet del UINavigationController llamado searchDisplayController al SearchDisplayController que acabamos de añadir a la vista. Normalmente el NavigationController será el File’s Owner del fichero, y así lo vemos en la captura de un poco más arriba.

Hasta ahora, solo hemos hablado de la parte visual, pero después de crear el SearchDisplayController y asignarlo a la propiedad en el ViewController, si introducimos texto, vemos como no pasa nada. El siguiente paso consiste en decir como vamos a mostrar los datos de la búsqueda.

Para mostrar los datos, una de nuestras clases tiene que implementar varios protocolos habituales de una UITableView, como son UITableViewDataSource y UITableViewDelegate. Como veis, al fin y al cabo el proceso se reduce a mostrar una vista reducida de nuestros datos, filtrada por la condición de búsqueda.

Como vemos en la captura anterior, los outlets del SearchDisplay controller respecto al origen de los datos, esta establecidos al File’s Owner.

En cuanto a la estrategia de implementación, se pueden seguir varias aproximaciones. Por un lado se puede hacer que la misma clase sea DataSource de ambas tablas, es decir, la tabla con todos los datos y la tabla con los datos de la búsqueda, sin embargo esta solución tiene el problema que los mismos métodos tienen que devolver cosas diferentes. Personalmente no me gusta nada esta solución.

Por otro lado, se pueden tener dos clases diferentes, sin embargo hay que tener en cuenta que el modelo de datos a la que acceden ambas clases, es compartido, ya que la búsqueda se realiza sobre los datos que esta mostrando el ViewController de turno.

Estas dos alternativas están pensadas a cuando la búsqueda se realiza sobre una tabla de datos, sin embargo, no tiene por que ser siempre así, la búsqueda podemos hacerla sobre cualquier vista que queramos. En tal caso no habrá mucho problema en unir en la misma clase que gestiona la vista, los métodos de gestión de la tabla de los resultados de la búsqueda.

A continuación os pongo el código de una implementación, el código no pretende ser eficiente, si no mostrar el funcionamiento 😉

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
    [filteredData release];
    filteredData = [[NSMutableArray alloc] init];
    for ( NSString* name in tableData )
    {
        if ([[name lowercaseString] rangeOfString:[searchText lowercaseString]].location != NSNotFound )
            [filteredData addObject:name];
    }
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [filteredData count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
    if ( cell == nil )
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"];
    
    cell.textLabel.text = [filteredData objectAtIndex:indexPath.row];
    return cell;
}

Ya que mucha parte del funcionamiento, esta embebido en los ficheros de Interface Builder, he subido el proyecto de prueba a github, por si alguien quiere echarle un ojo.


La configuración de nuestra aplicación en el menu general

abril 26, 2011

Seguro que en múltiples ocasiones al entrar en la configuración de nuestro teléfono hemos visto listadas un montón de aplicaciones en la parte inferior de la pantalla. Esto es así porque a la hora de proporcionar un punto para configurar nuestra aplicación tenemos dos opciones, una es meterla dentro de la propia aplicación y la otra es integrarla en el menú de configuración del sistema.

Sin duda la opción de hacerlo nosotros en la aplicación puede parecer a priori la mas fácil, pues no tenemos que aprender una nueva forma de hacer las cosas, pero como veremos en esta entrada, integrarse en el menú global de configuración es sencillo y de esta manera nos quitaremos el gestionar una pantalla mas dentro de nuestro programa.

La única limitación que se nos impone es que las opciones que queramos configurar se adapten a los controles que el sistema nos ofrece. Aunque sinceramente, la mayoría de las opciones suelen ser cajas de texto, sliders o booleanos de ON/OFF.

El primer paso para añadir nuestro programa al menú de configuración, es incorporar a nuestro proyecto un bundle de tipo “settings”, dicho bundle va a tener uno o varios ficheros de tipo plist donde vamos a especificar los elementos de configuración de nuestra aplicación.

Normalmente la opción mas sencilla será usar el editor de ficheros plist integrado que viene en el xcode, pues en el caso de los settings, automáticamente nos detectará el tipo de elemento y nos mostrará las opciones disponibles.

Aún así, si nos gusta mirar el código de las cosas 😉 como seguro que es el caso, podemos ver el XML que se genera y tocar ahí mismo los valores de configuración de cada componente. Como podemos ver en la siguiente captura.

Para mas información sobre las propiedades de cada elemento, podemos visitar la documentación oficial de Apple, donde se describen todas posibilidades a la hora de describir la interfaz de configuración.

Una de las cosas mas interesantes es que no estamos limitados a una sola pantalla de configuración, podemos añadir una estructura jerárquica de pantallas de configuración.

Para ello, uno de los elementos del fichero plist, es “PSGroupSpecifier”, que nos permite especificar otro fichero plist que será el que contenga la pantalla en el siguiente nivel de jerarquía, así podemos crear la configuración tan compleja como la necesitemos

Una vez que tenemos nuestro bundle listo, el siguiente paso es recuperar esos valores en nuestro código. Una vez mas, este proceso es bastante sencillo gracias a la clase NSUserDefaults. Este método tiene los típicos getters y setters para obtener y configurar los valores de la configuración, así por ejemplo el código para recuperar el valor del campo de configuración que describimos en el plist seria:

NSUserDefaults *settings = [NSUserDefaults standardUserDefaults];
NSLog(@"Players: %@",[settings integerForKey:@"players"]];
NSLog(@"Active Push Notifications: %@", [settings boolForKey:@"enable_push"]

Como hemos visto, integrar nuestra aplicación en el menú global de configuración es tremendamente sencillo, y gracias a su potencia a la hora de describir nuestros parámetros de configuración, nos va a ahorrar el hacer dichas pantallas dentro de nuestra aplicación.


Desmitificando Core Data para iOS

marzo 6, 2011

Seguro que en muchas ocasiones hemos leido el nombre de Core Data, y puede que en esas ocasiones nos haya parecido que seria una librería compleja de utilizar.

Si hay algo constante en la gran mayoría de las aplicaciones es, su necesidad de guardar datos en el medio de almacenamiento que el dispositivo ofrezca. Esta necesidad es la que vamos a poder salvar con Core Data, y de una manera bastante sencilla.

Concretamente, en esta entrada vamos a hablar de la versión para iPhone de Core Data, que en sus funcionalidades básicas, poco tiene que envidiar a su hermana mayor de OS X.

A diferencia de algunos tutoriales que andan por ahí, que empiezan desde una aplicación vacía, aquí vamos a ver como incorporar Core Data a nuestra aplicación ya empezada.

Personalmente, Core Data me ha sorprendido, pensaba que sería mucho mas compleja y complicada de incorporar a una aplicación, pero siguiendo la linea de muchas cosas de Apple, la librería es muy sencilla de utilizar. Pero, no adelantemos acontecimientos 🙂

El primer paso es entender como funciona Core Data. Para ello, nos vamos a ayudar del siguiente gráfico:

Como vemos, hay tres niveles, arriba del todo están nuestros objetos, que o bien son instancias de NSManagedObject, o bien heredan de él. Como en la vida real ;), nuestros objetos viven en un contexto, aquí esta representado por el NSManagedObjectContext. Este contexto va a ser el que alojara nuestros objetos dotándoles de los mecanismos de persistencia que Core Data proporciona. Por ejemplo, si queremos crear un objeto, en lugar de construirlo por nuestra cuenta, le pediremos al contexto que nos genere uno. Y de la misma manera cuando queramos guardar el objeto a disco, le diremos al contexto que lo guarde.

En la parte mas baja, se encuentra el Persistent Store Coordinator, que, como su nombre indica, es el encargado de coordinar la escritura en el almacenamiento. Realmente nosotros, salvo para indicarle donde esta el almacenamiento, no vamos a trabajar mucho mas con él.

Finalmente, el ultimo elemento del gráfico es el modelo que describe como son nuestros objetos. Eso es lo que se conoce como el Managed Object Model, y que esta representado por el fichero xcdatamodeld y que podremos editar de una forma bastante cómoda usando xcode.

Una vez visto (de forma breve y resumida) la arquitectura de Core Data, vamos a ponernos manos a la obra y vamos a dotar de persistencia a nuestra aplicación.

Para ello, el primer paso es incluir dentro de nuestros frameworks, el de Core Data.

El siguiente paso es crear el modelo de los objetos que vamos a utilizar, para ello, añadimos un nuevo fichero de tipo Core Data Model a nuestro proyecto, lo que creara un fichero de tipo xcdatamodeld.

Si abrimos dicho fichero, xcode nos mostrará un cómodo editor para crear nuestras entidades, por ejemplo vamos a crear una clase que represente a un coche.

Ahora vamos al código de verdad. Para guardar objetos en el contexto, necesitamos acceder al propio contexto, y lo vamos a necesitar desde múltiples sitios, por ello, lo mejor es crearnos una clase que sea accesible desde todos los sitios y que “guarde” la instancia del contexto. Cogiendo el código que Apple pone de ejemplo cuando creamos una aplicación que use code data, dicha clase sería algo como:


@interface CoreDataManager : NSObject {
    
}

@property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext;
@property (nonatomic, retain, readonly) NSManagedObjectModel *managedObjectModel;
@property (nonatomic, retain, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator;

- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;

+ (CoreDataManager*) sharedInstance;

@end

@implementation CoreDataManager

@synthesize managedObjectContext=__managedObjectContext;
@synthesize managedObjectModel=__managedObjectModel;
@synthesize persistentStoreCoordinator=__persistentStoreCoordinator;

static CoreDataManager* _sharedInstance;

+ (CoreDataManager*) sharedInstance
{
    if ( ! _sharedInstance )
        _sharedInstance = [[CoreDataManager alloc] init];
    
    return _sharedInstance;
}

- (id)init 
{
    self = [super init];
    if (self) {
        _sharedInstance = self;
    }
    return self;
}

- (void) dealloc 
{
    [__managedObjectContext release];
    [__managedObjectModel release];
    [__persistentStoreCoordinator release];
    [super dealloc];
}
- (void)saveContext
{
    NSError *error = nil;
    NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
    if (managedObjectContext != nil)
    {
        if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error])
        {
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        } 
    }
}

#pragma mark - Core Data stack

- (NSManagedObjectContext *)managedObjectContext
{
    if (__managedObjectContext != nil)
    {
        return __managedObjectContext;
    }
    
    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil)
    {
        __managedObjectContext = [[NSManagedObjectContext alloc] init];
        [__managedObjectContext setPersistentStoreCoordinator:coordinator];
    }
    return __managedObjectContext;
}

- (NSManagedObjectModel *)managedObjectModel
{
    if (__managedObjectModel != nil)
    {
        return __managedObjectModel;
    }
    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"PruebaCoreData" withExtension:@"momd"];
    __managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];    
    return __managedObjectModel;
}

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
    if (__persistentStoreCoordinator != nil)
    {
        return __persistentStoreCoordinator;
    }
    
    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"PruebaCoreData.sqlite"];
    
    NSError *error = nil;
    __persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error])
    {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }    
    
    return __persistentStoreCoordinator;
}

#pragma mark - Application's Documents directory
- (NSURL *)applicationDocumentsDirectory
{
    return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
@end

Una vez que el contexto es accesible desde otros puntos del nuestro programa, el siguiente paso es guardar un objeto en el almacenamiento, para ello le pedimos al contexto que nos de una nueva instancia de la clase, la rellenamos con los datos y le decimos al contexto que la guarde. El código que lo hace sería así:

NSManagedObject* myCoche = [NSEntityDescription insertNewObjectForEntityForName:@"Coche" inManagedObjectContext:[CoreDataManager sharedInstance].managedObjectContext];
[myCoche setValue:@"Ford" forKey:@"Fabricante"];
[myCoche setValue:@"Crown Victoria" forKey:@"Modelo"];
[myCoche setValue:[NSNumber numberWithInt:12000] forKey:@"Precio"];
[[CoreDataManager sharedInstance] saveContext];

Como veis, el funcionamiento no podía ser mas fácil. Con muy poco código, tenemos persistido nuestro objeto en un almacén de datos.

Finalmente, el último paso seria recuperar los objetos que hay en el almacén, para ello necesitamos una nueva clase, llamada NSFetchRequest. En esta entrada nos vamos a quedar en un nivel básico, ya que el propósito es ver que componentes entran en juego cuando usamos Core Data, por lo que vamos únicamente a recuperar todos nuestros objetos, sin poner ningún tipo de filtro.

Es evidente que vamos a necesitar un mejor control de como recuperamos nuestros objetos, para ello lo mejor es acudir directamente a la documentación sobre esta clase y quizás a una futura entrada que explique en detalle como se recuperan objetos usando esta clase 😉

Volviendo a la recuperación de datos, el proceso consta de crear el FetchRequest, especificar el tipo de entidad que vamos a recuperar, en nuestro caso, un Coche, y ejecutar el request, obteniendo así un array con los objetos que estaban en el almacén.

NSFetchRequest *req = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Coche" inManagedObjectContext:[CoreDataManager sharedInstance].managedObjectContext];
    [req setEntity:entity];
    NSError *error;
    NSArray *objects = [[CoreDataManager sharedInstance].managedObjectContext executeFetchRequest:req error:&error];

Como se suele decir, lo difícil es empezar, y espero que con esta entrada ese paso este dado. Queda mucho Core Data por explorar, cosas como las relaciones entre entidades, o los filtros en los request son cosas muy comunes y que vamos a necesitar usar. Sin duda, son materia para futuras entradas 🙂


Categoría para traducir entidades html en NSString

septiembre 20, 2010

Recientemente desarrollando para el iOS, me encontré con la necesidad de eliminar las entidades html de una cadena de texto.

Para el que no lo sepa, las entidades dentro de HTML, o en cualquier lenguage de marcas, son lo mas parecido a una secuencia de escape, es decir, una cadena que representa a un caracter que originalmente no esta permitido. Por ejemplo, y como parece obvio, si queremos poner el caracter ‘<‘ en HTML, no podemos ponerlo directamente, pues forma parte del propio lenguage. Por ello, si queremos escribir dicho carácter tendremos que poner <.

La principal característica de las entidades de un lenguage de marcas, es que comienzan con ‘&’ y acaban con ‘;’.

Dentro de la API de manejo de cadenas de UIKit, existe un método para codificar URLs, que aunque pueda parecer similar, no lo es. Pues las URLs no tienen nada que ver con el lenguage HTML, solo nos indican la forma de acceder a los documentos que estan hechos con HTML 😉

Dichos métodos son, stringByAddingPercentEscapesUsingEncoding: y stringByReplacingPercentEscapesUsingEncoding:, y sustituyen los caracteres especiales de las URLs por sus equivalentes “escapados” usando porcentajes, como por ejemplo el símbolo del $ la convertirá en %24.

Pero sin embargo no hay ninguna función para transformar las entidades en sus caracteres equivalentes.

La primera solución que se nos puede ocurrir es usar el mensaje stringByReplacingOccurrencesOfString:withString: por cada entidad. Y aunque funciona, es bastante penalizador desde el punto de vista del rendimiento, ya que si tenemos el siguiente código.

NSString* cad = [NSString stringWithString:@"&lt;&apos;&amp;&apos;&gt;"];
	NSLog(@"%@", [[[[cad stringByReplacingOccurrencesOfString:@"&lt;" withString:@"<"]
				  stringByReplacingOccurrencesOfString:@"&gt;" withString:@">"]
				  stringByReplacingOccurrencesOfString:@"&amp;" withString:@"&"]
				  stringByReplacingOccurrencesOfString:@"&apos;" withString:@"'"]);

Recorrerá la cadena entera tantas veces como entidades queramos sustituir, lo que para cadenas largas puede ser un gasto bastante grande e innecesario.

Después de buscar por internet, no encontré nada que me convenciera, asi que tome el camino del medio, y hice una categoria de NSString, que recorre la cadena y sustituye las ocurrencias, de las entidades por sus caracteres.

Al ser una categoria, no hace falta mas que incluir el fichero .h y llamarlo sobre cualquier objeto NSString.

@interface NSString (RemoveHtmlEntities)

- (NSString*) stringByRemovingHtmlEntities;

@end

@implementation NSString (RemoveHtmlEntities)

- (NSString*) stringByRemovingHtmlEntities {
	NSMutableString* newStr = [[NSMutableString alloc] init];
	NSUInteger i = 0;
	unichar c = 0;
	NSUInteger strLen = [self length];
	while (i < strLen) {
		c = [self characterAtIndex:i];
		if ( c == '&' ) {
			if ( [self rangeOfString:@"amp;" options:NSCaseInsensitiveSearch range:NSMakeRange(i, (5>(strLen-i))?strLen-i:5)].location != NSNotFound ) {
				[newStr appendFormat:@"&"];
				i += 5;
			} else if ([self rangeOfString:@"lt;" options:NSCaseInsensitiveSearch range:NSMakeRange(i, (4>(strLen-i))?strLen-i:4)].location != NSNotFound) {
				[newStr appendFormat:@"<"];
				i += 4;
			} else if ([self rangeOfString:@"gt;" options:NSCaseInsensitiveSearch range:NSMakeRange(i, (4>(strLen-i))?strLen-i:4)].location != NSNotFound) {
				[newStr appendFormat:@">"];
				i += 4;
			} else if ([self rangeOfString:@"quot;" options:NSCaseInsensitiveSearch range:NSMakeRange(i, (6>(strLen-i))?strLen-i:6)].location != NSNotFound) {
				[newStr appendFormat:@"\""];
				i += 6;
			} else if ([self rangeOfString:@"apos;" options:NSCaseInsensitiveSearch range:NSMakeRange(i, (6>(strLen-i))?strLen-i:6)].location != NSNotFound) {
				[newStr appendFormat:@"'"];
				i += 6;
			} else {
				[newStr appendFormat:@"&"];
				i++;
			}
		} else {
			[newStr appendFormat:@"%c", c];
			i++;
		}
	}
	return [newStr autorelease];
}

@end

Como veis, solo transforma las entidades que necesitaba en el momento de desarrollo, pero es trivial añadir mas clausulas “else if” al código 😉

Un posible uso del código sería

	NSString* cad = [NSString stringWithString:@"&lt;&apos;&amp;&apos;&gt;"];
        NSLog(@"%@", [cad stringByRemovingHtmlEntities]); 
       // Imprime <'&'>

Dashcode, como hacer widgets para OSX

diciembre 20, 2009

Cuando hablamos sobre desarrollo en OSX, raudo y veloz aparece en nuestra mente el nombre de XCode. Si bien es cierto que es la herramienta de referencia ( Sin olvidarnos de Interface Builder, claro), hay otra alternativa para desarrollar software en OSX.

Esta otra manera es mas o menos reciente, y la aplicación que nos va ayudar a crearla se llama Dashcode. La primera versión del sistema operativo de apple en el que podemos usar esta herramienta es en Leopard 10.5, y forma parte del grupo de herramientas para desarrolladores. Actualmente se puede usar Dashcode tanto para crear widgets para el Dashboard como para crear webs personalizadas para el iPhone. Este último dato es lo que lo convierte en una alternativa para desarrollar aplicaciones para el smartphone de apple.

Esta aproximación al desarrollo de aplicaciones para el iPhone tiene como gran punto negativo las limitaciones que impone el que realmente estas desarrollando una aplicacion web, pero pero como puntos positivos tiene el hecho de que no hace falta comprar ninguna licencia para desarrollar, y que la dificultad de desarrollo con respecto a la programación de aplicaciones nativas es bastante mas asequible.

Uno de los aspectos que hacen el desarrollo más sencillo es el lenguaje escogido para desarrollar dichas aplicaciones. HTML + Javascript hacen las veces de Objective-C en Dashcode, nuestros widgets realmente se pueden asemejar a porciones de páginas web. Aún así esta eleccion no nos debe hacer pensar que estamos limitando las posibilidades, pues en el caso de los widgets para el dashboard podremos usar mucha de la funcionalidad que tambien podemos acceder desde una aplicación Cocoa, ya que desde javascript podemos acceder a estos modulos mas cercanos al Sistema Operativo.

Para muestra, un boton, en el siguiente enlace podreis ver algunos de los widgets actuales para dashcode.

Junto con Dashcode se incorpora un montón de componentes “prefabricados” como listas, botones, paneles, que podemos usar en el desarrollo de nuestros widgets.

El propio IDE también nos facilita mucho el trabajo, sin tener mucha idea de como funciona todo podemos realizar ejemplo sencillo en cuestion de minutos. Estas ayudas se traducen en autocompleting de Javascript y HTML, edición gráfica de los widgets, y debugger incluido.

Aunque tampoco debemos dejarnos engañar, como con casi todo, manejar a fondo los componentes ( llamados “parts” ) que se pueden insertar en los widgets lleva su tiempo de aprendizaje.

En general podemos concluir que siendo consciente de sus limitaciones, es una gran alternativa al desarrollo tradicional de aplicaciones.


Gmail Push en iPhone

septiembre 23, 2009
Si algo llevamos esperando los usuarios de gmail y poseedores del iphone es el poder usar Push como los usuarios de otros dispositivos pueden desde hace mucho tiempo.
Pues bien, ese día ha llegado, desde ayer podemos usar push, no solo para consultar el correo, si no para sincronizar los calendarios y los contactos.
Si alguien no entiende inglés o prefiere leerlo en español, aquí va mi granito de arena ?
La configuración es sencilla, lo primero de todo es que necesitamos un iphone con el firmware 3.0 o superior.  Ya que se van a sincronizar datos como los contactos, se recomienda hacer un backup de dichos datos antes de configurarlo, por si las moscas.
Para activar el push debemos configurar una nueva cuenta de correo, para ello nos dirigimos a Cuentas de correo dentro de Ajustes y elegimos como nueva cuenta una de Exchange. Google utiliza el protocolo ActiveSync para gestionar el push.
El siguiente paso es rellenar los datos de conexión de la cuenta, para ello rellenamos los datos de la siguiente manera:
En el campo de dirección de correo, ponemos nuestra dirección completa de correo. Por ejemplo zbutton@gmail.com
Dejamos el campo de Dominio vacio
En el campo de usuario, volvemos a introducir nuestra dirección completa de correo, de nuevo zbutton@gmail.com
En el campo de contraseña, introducimos nuestra contraseña
Una vez rellenados estos campos, pulsamos en continuar. Se nos mostrará un mensaje de error, diciendo que es imposible verificar el certificado, no os preocupéis es normal. Pulsamos en aceptar y saldrá un nuevo campo que deberemos rellenar.
El nuevo campo es el servidor, y lo rellenamos con m.google.com. Pulsamos en Siguiente.
La siguiente pantalla nos pregunta que información queremos sincronizar, aparte del correo podemos sincronizar los contactos y los calendarios, pero ojo!, si sincronizamos ambas cosas podemos perder los datos que actualmente tenemos en el iphone. Cuando activamos alguna de las opciones se nos preguntará qué queremos hacer con los datos que actualmente están en el teléfono. Si decidimos conservarlos, puede que haya problemas de duplicados, si decidimos no conservarlos, los datos se borrarán.
Una vez configurado la cuenta debemos asegurarnos que en el modo de recuperar la información tenemos activado el push, y voila, cuando nos llegue un correo, el teléfono nos avisará sin tener que consultar nosotros el correo.
Solo hay una pequeña pega que poner y es que solo se puede tener una cuenta de Exchange a la vez, por lo que si ya tenemos previamente una cuenta configurada con este método, no podremos usar el push en el gmail. No todo podía ser perfecto.

Si algo llevamos esperando los usuarios de gmail y poseedores del iphone es el poder usar Push como los usuarios de otros dispositivos pueden desde hace mucho tiempo.

Pues bien, ese día ha llegado, desde ayer podemos usar push, no solo para consultar el correo, si no para sincronizar los calendarios y los contactos.

La información original esta en la web de google.

Si alguien no entiende inglés o prefiere leerlo en español, aquí va mi granito de arena 🙂

La configuración es sencilla, lo primero de todo es que necesitamos un iphone con el firmware 3.0 o superior. Ya que se van a sincronizar datos como los contactos, se recomienda hacer un backup de dichos datos antes de configurarlo, por si las moscas.

Para activar el push debemos configurar una nueva cuenta de correo, para ello nos dirigimos a Cuentas de correo dentro de Ajustes y elegimos como nueva cuenta una de Exchange. Google utiliza el protocolo ActiveSync para gestionar el push.

push1

push 2

El siguiente paso es rellenar los datos de conexión de la cuenta, para ello rellenamos los datos de la siguiente manera:

• En el campo de dirección de correo, ponemos nuestra dirección completa de correo. Por ejemplo zbutton@gmail.com

• Dejamos el campo de Dominio vacio

• En el campo de usuario, volvemos a introducir nuestra dirección completa de correo, de nuevo zbutton@gmail.com

• En el campo de contraseña, introducimos nuestra contraseña

Una vez rellenados estos campos, pulsamos en continuar. Se nos mostrará un mensaje de error, diciendo que es imposible verificar el certificado, no os preocupéis es normal. Pulsamos en aceptar y saldrá un nuevo campo que deberemos rellenar.

El nuevo campo es el servidor, y lo rellenamos con m.google.com. Pulsamos en Siguiente.

push 3

La siguiente pantalla nos pregunta que información queremos sincronizar, aparte del correo podemos sincronizar los contactos y los calendarios, pero ojo!, si sincronizamos ambas cosas podemos perder los datos que actualmente tenemos en el iphone. Cuando activamos alguna de las opciones se nos preguntará qué queremos hacer con los datos que actualmente están en el teléfono. Si decidimos conservarlos, puede que haya problemas de duplicados, si decidimos no conservarlos, los datos se borrarán.

push 4

Una vez configurado la cuenta debemos asegurarnos que en el modo de recuperar la información tenemos activado el push, y voila, cuando nos llegue un correo, el teléfono nos avisará sin tener que consultar nosotros el correo.

Solo hay una pequeña pega que poner y es que solo se puede tener una cuenta de Exchange a la vez, por lo que si ya tenemos previamente una cuenta configurada con este método, no podremos usar el push en el gmail. No todo podía ser perfecto.