lunes, 24 de octubre de 2011

AlertMessage, una forma de mejorar UIAlertView.

Con la clase UIAlertView para poner un simple mensaje que tuviera un par OK/Cancel, tenía que dividir mi código en 2 partes!, es que para enterarme si el usuario presiono un botón u otro hay que colgarse de un delegate. Yo entiendo, tiene toda la lógica, pero tener que separar algo que naturalmente va junto, no me gusta nada. Y la cosa empeora si hay más de un Alert en nuestro Controller: el resultado de cada uno de ellos llega a la misma función del delegate, por lo cual, algo que es feo de por sí, termina siendo además caótico!

Eran tiempos de iOS 3 y no se me ocurrió una buena forma de mejorarlo. Pero con iOS 4 y los code-blocks, la solución llegó. Por eso les presento un wrapper llamado AlertMessage, que soluciona los dos problemas que no me dejaban dormir:



código compacto: el código a ejecutar luego del alerta se define en el mismo lugar donde se crea el AlertMessage y no en otro lugar.
no hay “bolsa de gatos”: no hay un delegate centralizado donde caen todos los Alertas, porque no hay más delegate que programar!
Este es el forma de usar AlertMessage:

creo el objeto
le asigno título y mensaje
le defino los botones
le defino el código que debe ejecutarse al momento en que se presionen cualquier de los botones
listo, momento de visualizar el Alert: show
Asi de simple. Les copio el .h y .m para que puedan probarlo y mejorarlo.

AlertMessage.h
//
// AlertMessage.h
//

#import

typedef void (^AlertMessageHandler)(int);

@interface AlertMessage : NSObject

@property (nonatomic, retain) NSString* titulo;
@property (nonatomic, retain) NSString* mensaje;

+ (id)alertMessage;

- (void)show;
- (void)agregarBoton:(NSString*)_texto;
- (void)ejecutarCodigo:(AlertMessageHandler)_codigo;

@end

AlertMessage.m

//
// AlertMessage.m
//

#import "AlertMessage.h"

@interface AlertMessage ()
{
UIAlertView* alert;
AlertMessageHandler codigo;
}

- (id)init;

@end

@implementation AlertMessage

@synthesize titulo, mensaje;

- (void)dealloc
{
self.titulo = nil;
self.mensaje = nil;
Block_release(codigo);
[alert release];
[super dealloc];
}

// Para el usuario, AlertMessage tiene una semantica similar a un autorelease: lo construye pero nunca lo mata. En realidad esto lo consigo suicidándolo en el delegate
// Debido a esto, el Code Analizer reporta un posible leak, asi que uso esta directiva para evitar que analice este método
#ifndef __clang_analyzer__

+(id)alertMessage;
{
return [[AlertMessage alloc] init]; // no hago autorelease, porque se "suicida" en el delegate
}

#endif

-(id)init;
{
self = [super init];
if (self) {
alert = [[UIAlertView alloc] init];
alert.delegate = self;
}
return self;
}

// aquí termino de completar el UIAlertView y lo displayo
-(void)show;
{
alert.title = self.titulo;
alert.message = self.mensaje;

[alert show];

}

// delego en addButtonWithTitle
-(void)agregarBoton:(NSString*)_texto;
{
[alert addButtonWithTitle:_texto];
}

// me quedo con la instancia de codigo a ejecutar cuando se cierra el UIAlertView
- (void)ejecutarCodigo:(AlertMessageHandler)_codigo;
{
codigo = Block_copy(_codigo);
}

#pragma mark -
#pragma mark Alert view delegate

- (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
// si hay codigo a ejecutar, lo hago
if (codigo) {
codigo(buttonIndex);
}
[self release]; // aquí se mata a si mismo
}

@end

Entre las mejoras, se me ocurren:

crear varios constructores, considerando los usos más habituales, como alertMessageWithOKCancel, etc. etc.
soporte para la propiedad cancelButtonIndex de UIAlertView
soporte en iOS 5 de la propiedad alertViewStyle de UIAlertView (propiedad muy interesante, que da la interfaz para poner un campo de texto en el alerta, algo que tarde o temprano vas a necesitar).

No hay comentarios:

Publicar un comentario