Vamos a realizar una pequeña aplicación para consultar el tiempo meteorológico. La aplicación terminada tendrá el aspecto que se muestra en la figura
Como se ve en la figura, la interfaz tiene 4 componentes, seleccionables mediante el panel de componentes gráficos de la esquina inferior derecha de Xcode:
Como ya hiciste en la aplicación de UADivino, conecta los componentes de la interfaz con el ViewController
:
Ctrl+arrastrar
desde el componente hasta el ViewController.h
, y cada uno generará un @property
. Crea outlets para la imagen, la etiqueta y el campo de textoViewController.m
. Cada action genera un método. Crea un action para el botón de “consultar tiempo”El estado del tiempo nos lo da un servicio externo, Openweather, que además de la web ofrece el API que vamos a usar.
Para obtener el tiempo en una localidad, con los mensajes traducidos a español y usando unidades del sistema métrico, hay que hacer una petición HTTP a la URL http://api.openweathermap.org/data/2.5/weather?lang=es&units=metric&q=
concatenándole la localidad a buscar. Por ejemplo si clicas en este enlace verás el tiempo para Alicante. El API devuelve los datos en formato JSON, que habrá que analizar para extraer la información que nos interese.
IMPORTANTE: la última versión de iOS tiene una característica llamada “Application Transport Security”, que impide realizar peticiones HTTP desde el código. Solo se pueden hacer peticiones HTTPS. Para poder saltarnos esta restricción tenemos que modificar el archivo
info.plist
del proyecto:Pulsa con el botón derecho sobre dicho archivo y elige
Open As > Source Code
.Despúes de la etiqueta
<dict>
de la línea 4 inserta estas líneas:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key><true/>
</dict>
Para hacer una petición HTTP en iOS podemos usar la clase NSURLSession
. Copia el siguiente código en el action asociado al botón y adáptalo a tus necesidades:
//IMPORTANTE: la siguiente sentencia asume que la localidad a consultar
//está en la variable "localidad". Cambia el código si lo necesitas
//stringWithFormat es similar al "sprintf" de C, sirve
//para montar una cadena con varios elementos con el formato deseado
NSString *cadQuery = [NSString stringWithFormat:@"http://api.openweathermap.org/data/2.5/weather?lang=es&units=metric&q=%@", localidad];
//Para conectarnos necesitamos un objeto NSURL
NSURL *urlQuery = [NSURL URLWithString:cadQuery];
//Los parámetros de la conexión son los usados "por defecto"
NSURLSession *sesion = [NSURLSession sharedSession];
//Un DataTask es una petición. Cuando se completa, se llama al "completionHandler"
NSURLSessionDataTask *tarea = [sesion
dataTaskWithURL:urlQuery
completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
//Convertimos el JSON en un NSDictionary
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSLog(@"%@", json);
}];
//Lo anterior solo define la petición. Esto la inicia
[tarea resume];
Aunque no está explícito en el código anterior, NSURLSession
usa implícitamente un thread adicional para no bloquear la interfaz de usuario. Además fíjate en que es asíncrono: nos avisa de cuándo ha respondido el servidor llamando al bloque completionHandler
.
Si ejecutas ahora la aplicación e introduces una ciudad en el campo de texto, en la consola de depuración debería aparecer el JSON que nos está enviando Openweather. Comprueba que efectivamente aparecen datos.
Al colocar el cursor en el campo de texto verás que aparece el teclado típico del móvil, y también verás que no se puede quitar aunque pulses en otra parte. Veremos cómo se hace por código, pero por ahora es más sencillo que en la ventana del simulador selecciones el menú de
Hardware > Keyboard
y selecciones la opciónToggle Sofware Keyboard
para ver/dejar de ver el teclado en pantalla.Para poder teclear con el teclado del ordenador en vez de tener que pulsar las teclas en pantalla, marca la opción
Hardware > Keyboard > Connect Hardware Keyboard
Si te fijas en el JSON que envía el servidor, verás que es un objeto complejo que a su vez tiene dentro otro objeto llamado weather
con la descripción del tiempo que hace ahora mismo. A su vez, este weather
tiene dentro un array de un solo objeto que es en realidad el que contiene los datos. La descripción en modo texto está en el campo description
. Por tanto, para llegar a la descripción haríamos
NSString *descripcion = json[@"weather"][0][@"description"];
Sí. El formato es complicado. Las quejas a Openweather, por favor.
Añade el código necesario para que la descripción aparezca en pantalla como texto de la etiqueta que has creado antes. Examina el código que has copiado y piensa dónde tienes que introducir las instrucciones. MUY IMPORTANTE: recuerda que las operaciones que actualizan la interfaz tienen que ejecutarse en el thread principal. Consulta las transparencias y/o apuntes para ver cómo obtener acceso a la cola de operaciones principal.
El API también devuelve el nombre de un icono que representa visualmente el estado del tiempo. Los iconos están en Internet y son accesibles concatenando una URL fija (http://openweathermap.org/img/w/
)+el nombre del icono+.png
. Por ejemplo si el API nos dice que el icono es 10d
la URL final será http://openweathermap.org/img/w/10d.png
.
El siguiente código hace una petición a la URL del icono y crea una imagen en memoria (un UIImage
, no se verá todavía en pantalla, solo está en memoria).
NSString *cadImg = [NSString stringWithFormat:@"http://openweathermap.org/img/w/%@.png", json[@"weather"][0][@"icon"]];
NSURL *urlImg = [NSURL URLWithString:cadImg];
NSData *dataImg = [NSData dataWithContentsOfURL:urlImg];
if (dataImg) {
//Si hemos llegado hasta aquí, los datos se han cargado OK.
//Creamos la imagen en memoria
UIImage *img = [[UIImage alloc] initWithData:dataImg];
NSLog(@"Imagen cargada con éxito");
}
Inserta el código anterior en el sitio apropiado. Comprueba que aparece el mensaje en la consola indicando que la imagen se ha cargado con éxito.
Una vez tengas esto funcionando, añade el código necesario para que la imagen se haga visible en pantalla. Para ello tendrás que asignar el UIImage
creado a la propiedad image
del outlet con la imagen. Recuerda que al ser una operación que actualiza el interfaz gráfico, esta asignación debes ejecutarla en la cola de operaciones principal.