ThXou

Ama la sabiduría. Desea el conocimiento

iOS: Aprendiendo Sobre Delegación, Protocolos Y La Clase UIAlertView

| Comments

En esta ocasión he querido hablar sobre la delegacion, un patrón muy común en Cocoa Touch que a muchos principiantes se nos puede atragantar, como ha sido mi caso. Es en si un concepto muy sencillo de entender, pero claro está, dependiendo de quien te lo explique. Espero explicarlo bien para que todos lo puedan entender, si no es así, decídmelo en los comentarios.

El concepto delegación en Cocoa Touch se refiere especificamente a que tu “delegas” a un objeto y lo dotas con la capacidad de responder a ciertos eventos ocurridos en otro objeto en particular. Este concepto es facilmente comprensible si lo miras desde el punto de vista de la necesidad que hay de que “alguien” deba recibir y manipular la información de ciertos eventos en ciertos objetos. Un ejemplo claro lo vemos en el GPS. Como podemos saber si el GPS ya encontró nuestra localización?, la información devuelta por el GPS está allí, pero alguien tiene que recibirla y trabajar con ella para poder mostrar esa localización. Pues, ese alguien es el delegado. El proceso de delagación se hace a través de la propiedad delegate. Esta propiedad no es común en todas las clases, solo algunas como UIAccelerometer, UIActionSheet, CLLocationManager, etc. la tienen ya que emiten mensajes para sus eventos. Entonces, asignamos a la propiedad delegate de un objeto la clase que queremos que sea la encargada de manipular los eventos de ese objeto y listo, el delegado ya está preparado para recibirlos y manipularlos.

Los eventos están representados en código a través de funciones (Métodos) las cuales son llamadas cada vez que el evento ocurre. El objeto delegado se encarga de implementar estas funciones para la cantidad de eventos que se envían dependiendo de cada objeto. Cada objeto delegado solo puede recibir mensajes para eventos de un solo objeto en particular, y estos pueden ser más de uno.

Aplicación práctica

Well. Siguiendo con mi idea de que todo se aprende mejor si lo llevamos a la práctica, he desarrollado una pequeña aplicación que utiliza la clase UIAlertView para mostrar una ventana como la que vimos en la entrada anterior sobre notificaciones locales. Esta ventana tiene unos botones, al presionarlos se altera el texto que hay en una etiqueta (UILabel) que está en la vista principal. Así de sencillo.

La clase UIAlertView nos permite representar una ventana de alerta en una vista en concreto y lo hacemos así:

1
2
3
4
5
    UIAlertView *ventana = [[UIAlertView alloc] initWithTitle:@"Mi Ventana"
                                                      message:@"Aprendiendo sobre delegación en thxou.com"
                                                     delegate:self
                                            cancelButtonTitle:@"Cancelar"
                                            otherButtonTitles:@"Limpiar Etiqueta!", @"Opción 1", @"Opción 2", nil];

El método initWithTitle:message:delegate:cancelButtonTitle:otherButtonTitles se encarga de crear el objeto llamado ventana, que es una instancia de UIAlertView, con una información por defecto. Pues bien, ventana tiene botones y al presionarlos se envía el mensaje alertView:clickedButtonAtIndex:.Cuando este mensaje es enviado se ejecuta el comportamiento por defecto que es simplemente cerrar la ventana de alerta.

Vamos a fijarnos en la etiqueta delegate del método en el código de arriba. Sabemos que pulsar un botón en la ventana es un evento que dispara el mensaje alertView:clickedButtonAtIndex:. Bien, al asignar self a la etiqueta delegate le estamos diciendo a ventana cual va a ser el encargado de gestionar sus eventos, en nuestro caso (Y como veréis en la mayoría de los casos) es self, nuestra misma clase ViewController.

[note]Veremos que en la mayoría de los casos el delegado es asignado de esta manera:

1
2
3
[objeto setDelegate:self];
//O también
objeto.delegate = self;

Este código cumple la misma función que en nuestro ejemplo.
[/note]

Ya que no queremos que al presionar los botones se ejecute el comportamiento por defecto, nuestra clase ViewController necesita implementar este método disparado por el evento y así le decimos a ventana que hacer cuando se presione un botón.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    switch (buttonIndex) {
        case 1:
            self.mensaje.text = @"";
            break;
        case 2:
            self.mensaje.text = @"Haz seleccionado la opción 1";
            break;
        case 3:
            self.mensaje.text = @"Haz seleccionado la opción 2";
            break;
        default:
            break;
    }
}

La variable buttonIndex contiene los indices para cada uno de los botones que contiene la ventana de alerta. Así que podemos hacer cosas diferentes dependiendo de el “caso”.

Este método, como ya hemos explicado, no es de nuestro delegado, simplemente estamos habilitados para personalizar la respuesta a un evento usando este método, pero no lo creamos nosotros ni definimos la cabecera del método. Por lo tanto el compilador nos va a lanzar una excepción al momento de compilar el código y la aplicación va a petar. Para evitar esto, tenemos que hacer que nuestro delegado “sea conforme” al protocolo donde está definido este método (relacionado a un evento) y todos los disparados por la ventana de alerta.

Representación del patrón delegate

Los protocolos son simples listas de métodos sin implementar. No son clases, pero si heredan de clases, tampoco podemos hacer instancias de ellos ni crear variables de instancia dentro de ellos. Sus métodos son implementados en las clases que “son conformes” a ese protocolo. Un protocolo delegado es aquel usado para la delegación, y en nuestro caso vamos a necesitar el protocolo delegado de UIAlertView que implementa el método alertView:clickedButtonAtIndex:, y este es: UIAlertViewDelegate. Cuando ocurre un evento en el objeto, se envía el mensaje correspondiente del protocolo delegado.

En un protocolo delegado podemos encontrarnos 2 tipos de métodos. Unos manipulan actualizaciones de información, como por ejemplo en el caso del GPS al principio, la localización será diferente siempre que te muevas, por lo tanto el método devolverá información diferente cada vez; Y otros, se envían como respuestas a entradas del usuario, como en nuestro caso, cuando el usuario pulsa un botón de la ventana de alerta. Hay algunos métodos que podrían entrar en una tercera categoría, y es el caso de alertViewShouldEnableFirstOtherButton:. En este método, la ventana de alerta pregunta al delegado si tiene que mostrar habilitado o deshabilitado el primero de los botones. La respuesta del delegado puede ser simplemente YES o NO. En nuestro caso he puesto NO, para que veas el comportamiento que tiene este método.

1
2
3
4
- (BOOL)alertViewShouldEnableFirstOtherButton:(UIAlertView *)alertView
{
    return NO;
}

Ya solo nos queda hacer que nuestro delegado “sea conforme” a UIAlertViewDelegate. Esto lo hacemos en la cabecera de nuestra clase ViewController.h en la declaración @interface, entre signos de mayor y menor.

1
2
3
4
5
@interface ViewController : UIViewController <UIAlertViewDelegate>
{
@private
    UILabel *mensaje;
}

He creado una etiqueta UILabel para mostrar mensajes dependiendo de que botón ha sido pulsado llamada: mensaje.

Listo, ya hemos terminado. Yo te recomiendo que analices el código y hagas cambios, muchos cambios, para que veas como funciona la clase y su protocolo delegado. Encontrarás enlaces a la documentación de Apple sobre este tema más abajo. En esta misma aplicación de ejemplo intenta añadir más métodos de UIAlertViewDelegate y así saber como funcionan.

Espero haberte ayudado a comprender este tema. Cualquier duda o sugerencia utiliza los comentarios.

UIAlertViewUIAlertViewDelegate

Comments