Hola iOS: introducción a la plataforma iOS y el lenguaje Objective-C

Introducción a iOS y al desarrollo en la plataforma

iOS

  • iOS está dividido en capas, como es habitual las capas superiores se apoyan en los servicios proporcionados por las inferiores.

  • Cocoa touch: contiene las funcionalidades de alto nivel, básicamente cuestiones relacionadas con el interfaz de usuario (multitouch, detección de gestos,…) pero también otras muy diversas: Airdrop, Mapkit para mostrar mapas en nuestra aplicacion, iAd, …

    • Media: contiene las tecnologías de video y audio, por ejemplo servicios de alto nivel como Airplay o APIs para gráficos 2D (Core Graphics) o animaciones (Core animation), gráficos 3D con OpenGL, procesamiento de audio (Core audio), …

    • Core services: contiene un conjunto de servicios básicos para las aplicaciones, por ejemplo la geolocalización, la concurrencia, el almacenamiento de datos con iCloud, SQLite o Core Data (para almacenar objetos de modo persistente),…

    • Core OS Funcionalidades básicas del sistema, como seguridad, control del hardware (bluetooth, accesorios externos, …).

  • En nuestras aplicaciones podemos usar los servicios proporcionados por cualquiera de las capas, pero se recomienda intentar usar los de las capas superiores si es posible. Por ejemplo, Cocoa Touch ofrece la posibilidad de usar los interfaces estándares del sistema para listar o seleccionar contactos de la agenda en nuestras aplicaciones. De esta forma nuestra aplicación tendrá un interfaz uniforme y coherente con el resto. Pero si necesitamos acceder a la información de contactos y queremos ofrecer un interfaz propio (o no necesitamos una interfaz) podemos usar las funcionalidades que nos ofrece la capa de “Core Services”.

Desarrollo en iOS

  • Para desarrollar aplicaciones en iOS empleamos un conjunto de lenguajes, herramientas de programación y librerías. A un nivel de abstracción algo más alto organizamos nuestro código siguiendo patrones de diseño software.

    • Frameworks: lo que en muchas otras plataformas se denomina librería. En Objective-C consisten físicamente en una librería dinámica y un conjunto de ficheros auxiliares, básicamente cabeceras (.h)

      • Lenguajes: hasta junio del año pasado el único que estaba soportado de manera oficial era Objective-C, que usaremos al menos en los primeros módulos del curso. Ahora Apple también soporta un nuevo lenguaje: Swift.

      • Herramientas: la más importante es el IDE de Apple, Xcode, que se integra además con herramientas adicionales como Instruments para depuración y pruebas de rendimiento, el Emulador para probar nuestras aplicaciones, ….

      • Patrones de diseño: tanto los APIs de iOS como la propia arquitectura que deben seguir las aplicaciones hace un fuerte uso de determinados patrones de diseño. El más omnipresente es el Modelo-Vista-Controlador, pero hay algunos más (delegation, publish/subscribe,…).

Introducción básica a Xcode

  • Xcode es un IDE que nos sirve tanto para escribir el código de nuestra aplicación iOS como para

    • Diseñar la interfaz gráfica

    • Ejecutar pruebas unitarias y de rendimiento

    • Depurar el código

    • Gestionar el control de versiones

    • Distribuir la aplicación

  • Áreas de trabajo: La pantalla de Xcode está dividida en 5 zonas:

    • Navegadores

    • Barra de herramientas

    • Editor

    • Utilidades

    • Área de depuración (inicialmente está oculta, y se muestra cuando se ejecuta la aplicación)

  • Vamos a crear una app que imprima “hola mundo” con NSLog, para

    • Escribir algo de código y compilarlo

    • Ver cómo se usa el emulador: cómo se ejecuta una aplicación y cómo se puede poner un breakpoint y depurar a nivel básico.

Introducción a Objective-C y a las aplicaciones iOS con una aplicación de ejemplo

Algunas características de Obj-C

  • Es una extensión orientada a objetos de C

  • Es mucho más dinámico que C++. Por ejemplo, se puede decidir el método a llamar en tiempo de ejecución, se puede definir una variable como un objeto de un tipo cualquiera (``id```).

  • Todos los objetos se crean en memoria dinámica, las variables son referencias, al estilo Java, pero debemos explicitar que son punteros, al contrario que en Java.

      //Obj-C
      NSString* cadena;
      //Java
      String cadena;
  • Se usan includes “al estilo C”, pero la sentencia #import impide automáticamente que el mismo fichero sea incluído dos veces, eliminando la necesidad de guardas de inclusión.

  • No se usa la sintaxis OO clásica de objeto.metodo(parametro) sino otra mucho más atípica: [objeto metodo: parametro]

  • La interfaz está separada de la implementación

  • La gestión de memoria se puede automatizar, aunque no usa recolección de basura, sino cuenta de referencias

La aplicación de ejemplo

Vamos a desarrollar una sencilla aplicación llamada UADivino. Podemos “preguntarle” algo en voz alta (que se pueda responder con sí/no) y al pulsar un botón la aplicación nos dará su respuesta.

Hacemos esta aplicación para ilustrar:

  • Cómo es el Objective-C básico

  • Qué estructura tiene el código de una aplicación iOS sencilla

  • Cómo se comunica el controlador con el modelo y con la vista

Modelo-Vista-Controlador

  • Todas las aplicaciones iOS siguen este patrón de diseño

  • Desde el punto de vista lógico nuestra aplicación se divide en tres componentes: modelo, vista y controlador

  • El modelo es el núcleo de la aplicación, qué es

  • La vista es el interfaz gráfico, cómo se presentan los datos

  • El controlador se comunica con ambos haciendo de nexo de unión. Más tarde veremos los distintos mecanismos de comunicación que hay en iOS.

  • Hay que tener claro que vista y modelo no deberían comunicarse directamente, siempre deberían hacerlo a través del controlador.

Estructura de una aplicación iOS

  • Para crear el nuevo proyecto 1. Iniciar la creación de nuevo proyecto desde la pantalla de bienvenida de Xcode: Create a new Xcode project

    1. En el siguiente diálogo, que permite elegir plantilla, seleccionar la de “Single View Application”

    2. En la pantalla de opciones, elegir como se muestra:

En Xcode 5, en esta pantalla se podía seleccionar un “prefijo” para las clases. En Objective C no hay namespaces, lo que impide que puedan haber dos clases con el mismo nombre. Como “parche”, en iOS/OSX era una práctica comúnmente aceptada preceder los nombres de las clases con un prefijo arbitrario para evitar colisiones. Con Xcode 6, Apple ha cambiado la práctica habitual y no recomienda los prefijos salvo para el desarrollo de frameworks, ya que en estos sí hay riesgo de colisión de nombres al estar hechos para ser usados en diferentes proyectos. En una aplicación normal es raro reutilizar código de otra y por tanto no hay riesgo de colisiones en los nombres.

  1. Finalmente, nos pedirá seleccionar la carpeta donde crear el proyecto. Automáticamente creará una carpeta con el mismo nombre del proyecto donde meterá todos los archivos. También nos preguntará si deseamos crear un repositorio Git para el proyecto. Marcad esta casilla, para poder probar su uso. Para ver más información sobre el uso de Git en Xcode, consultad el apéndice correspondiente.

Si no se marca la opción de Git es posible crear luego el repositorio de forma manual (con git init … etc) pero no con Xcode. Para ver cómo crear el repositorio manualmente, por ejemplo consultar el apartado “Creating a Git repository” del tutorial “Understanding Git Source Control in Xcode

  • Si echamos un vistazo al código generado por Xcode podremos ver que tiene la siguiente estructura, común a todas las aplicaciones iOS

  • El esquema anterior es genérico, en nuestro caso concreto:

    • Por ahora no hay modelo, ya que ¡crearlo es nuestro trabajo!

    • El UIApplication se crea desde la función main que está en Supporting files/main.m

    • El application delegate se ha creado automáticamente y se llama AppDelegate. Aquí es donde metemos el código “global” de la aplicación

    • Solo hay una vista y un controlador. El controlador es la clase ViewController. Para la vista no tenemos código Obj-C sino que la editamos gráficamente con el Main.storyboard

  • En el área del navegador, a la izquierda de la pantalla, podremos ver la estructura del proyecto recién creado. Veremos que está dividido en tres carpetas, o grupos: uno para los fuentes, otro para las pruebas unitarias y otro para el producto final (la aplicación compilada).

En Xcode los grupos o groups son simplemente una forma interna de organizar el código. Son carpetas “virtuales” que no tienen por qué corresponderse con carpetas “reales” del sistema de archivos. Como ejemplo, podéis pulsar con botón derecho sobre el icono del proyecto y seleccionar “Show in finder” para ver la estructura de carpetas en el Finder (el explorador de archivos de OSX). Podréis ver que los grupos UAdivino y UAdivinoTestssí se corresponden con carpetas del sistema de archivos, pero no así products o UAdivino/Supporting files.

Implementación del modelo

  • En resumen:

    • Es el núcleo de nuestra aplicación, la “lógica de negocio”

    • Debe ser independiente del interfaz, por lo que no se comunicará directamente con la vista

  • Nuestra “lógica de negocio” es muy simple, se limitará a darnos una respuesta elegida al azar de entre las posibles. Crearemos una clase que implemente esto.

  • Crear la clase UADivinoModel: Menú File > New > File... y en la categoría iOS elegir Cocoa Touch class

  • Automáticamente se creará un fichero de interfaz pública (.h) y otro de implementación (.m).

  • Añadir un método en el fichero de la interfaz:

    - (NSString\*) obtenerRespuesta;

  • implementar el método en el fichero de implementación. Por el momento solo debería dar las respuestas “SI” o “NO” con una probabilidad del 50%

    • Ayuda: la función arc4random() es similar al rand() de C. Por ejemplo para obtener enteros entre 0 y 9 haríamos: arc4random()%10.

Constructores

  • Crear un constructor en el que se inicialice un array de respuestas

Más sobre métodos

  • Añadir un método con argumentos: addRespuesta, para insertar una nueva posible respuesta en el array, con un argumento NSString*.

  • Tendremos que cambiar el NSArray por un NSMutableArray

Propiedades

  • Añadirle a UAdivino un nombre: Zoltar, Rappel, …

  • El compilador “sintetiza” automáticamente un getter y un setter. Por convenio el getter tiene el mismo nombre que la propiedad y el setter comienza por ``set```(al estilo Java).

Interfaz gráfico: vista y controlador

  • En el panel de la derecha del todo desmarcar la casilla “Use size classes”

  • Añadir un label para explicar la mecánica de UAdivino “formula en voz alta una pregunta y pulsa el botón para obtener la respuesta”

  • Añadir un botón “obtener Respuesta”

  • Crear un action vinculado al botón y en el ViewController.h a un nuevo método del controller “botonPulsado”

  • Crear un outlet vinculado al label y a una nueva propiedad en el ViewController.h

Asset catalogs

  • La mayoría de aplicaciones tienen imágenes asociadas al interfaz de usuario. Como mínimo deberían tener un icono y una imagen de launch, que aparece mientras se carga la aplicación. Además durante la ejecución se pueden mostrar más imágenes incluidas en el bundle de la aplicación (no son descargadas de la red en tiempo real). Para organizar las imágenes de modo sencillo podemos usar los Asset catalogs

  • Por defecto cada proyecto tiene inicialmente un catálogo de imágenes vacío, que aparece en el navegador con el nombre Images.xcassets

  • Para los iconos y launch image usaremos formato .png y los tamaños recomendados. Podemos consultarlos por ejemplo en las Human Inteface Guidelines de Apple

  • Podemos añadir una imagen al catálogo arrastrándolas allí dentro desde el Finder o bien pulsando con el botón derecho en el catálogo y seleccionando Import.... En realidad lo que estamos creando es un “image set” más que una única imagen física. Para cada imagen podemos tener la versión en 1x, 2x y 3x. iOS usará automáticamente la apropiada para la resolución del dispositivo actual.

  • Cada “image set” tiene un nombre, que no tiene por qué coincidir con el nombre físico del/los fichero/s. Para cargar la imagen en nuestro código podemos usar el método de clase imageNamed:

UIImage *imagen = [UIImage imageNamed:@"saludo"];

Foundation framework

El framework Foundation define un conjunto de clases básicas y de utilidades que no están directamente incluídas en Objective-C, como colecciones, cadenas, fechas … Además define algunos elementos importantes como la raíz de la jerarquía de clases y algunos tipos primitivos para mejorar la portabilidad.

Tipos primitivos de C vs tipos primitivos de Foundation/Cocoa

  • Como Objective-C es compatible con C podemos seguir usando en nuestros programas los tipos int, float, double,…

  • En Foundation también existen NSInteger y NSUInteger como sustitutos de las variantes de int. Son simplemente typedef definidos como enteros con la longitud apropiada para la plataforma (32/64 bits). Es decir, no son objetos sino tipos primitivos, y se recomienda su uso por razones de portabilidad.

  • Algo similar ocurre con CGFloat, usado ampliamente en Cocoa cuando se trabaja con números reales.

Clases básicas

  • En Foundation existe el concepto de objeto mutable e inmutable inmutable significa que no se pueden insertar, eliminar o cambiar elementos de la colección. Para estas operaciones debemos usar objetos mutables. Por ejemplo, las cadenas NSSString que hemos visto hasta ahora son objetos inmutables.

NSObject: la raíz de la jerarquía de clases

  • Todas las clases deben heredar de una clase base, en caso contrario dará error de compilación. Lo habitual es hacer que nuestras clases hereden de NSObject, la “clase raíz” de Foundation.

Esto es similar a otros lenguajes, por ejemplo Java, en la que todas las clases deben heredar de Object. Lo que ocurre es que en Java se hace implícitamente mientras que en Objective-C se debe especificar de manera explícita. De hecho en versiones antiguas de Java también se debía hacer explícitamente.

  • La clase NSObject incluye una serie de métodos de utilidad para nuestras clases, entre otros:

    • initialize es un método de clase llamado cuando ésta se carga por primera vez. Puede servir para inicializar variables estáticas.

    • En los dos siguientes apartados vamos a ver los métodos de NSObject para copiar objetos y obtener información sobre la instancia actual.

Copia de objetos

  • los métodos copy/mutableCopy: sirven para hacer una copia inmutable/mutable de un objeto, respectivamente.

  • Con clases de Foundation/Cocoa, podremos hacer una copia usando estos métodos cuando la clase en cuestión sea conforme al protocolo NSCopying. Podremos comprobar este extremo en la documentación

Posteriormente veremos más a fondo los protocolos en Objective-C. Por ahora nos basta con saber que más o menos equivalen a los Interface de Java

// La cadena original es inmmutable
NSString *cadena = @"Mi cadena";
NSString *copiaInmutable = [cadena copy];
NSMutableString *copiaMutable = [cadena mutableCopy];
// La cadena original es mutable
NSMutableString *cadenaMutable = [NSMutableString stringWithCapacity: 32];
NSString *copiaInmutable = [cadenaMutable copy];
NSMutableString *copiaMutable = [cadenaMutable mutableCopy];
  • Con clases propias, para que copy funcione, debemos

    1. Implementar un método copyWithZone (al que copy acaba llamando). En este método debemos devolver la copia. Para ayudarnos podemos hacer uso de NSCopyObject, que hace la copia shallow del objeto.

    2. Especificar que nuestra clase es conforme a NSCopying.

  • Podéis ver más detalles del proceso anterior por ejemplo en este tutorial

  • Con clases propias, para mutableCopy debemos hacer lo mismo pero implementando un método mutableCopyWithZone

Información sobre una instancia

NSObject implementa una serie de métodos que ofrecen información sobre una instancia y que podemos sobreescribir para adaptar a nuestras necesidades. Como ahora veremos, la mayoría de clases de Foundation ya los sobreescriben.

  • isEqual: como siempre se utilizan referencias para los objetos, el operador == lo que hará es comprobar si apuntan a la misma dirección de memoria. Si queremos comprobar igualdad de contenido, podemos usar isEqual.

    • La mayoría de clases de Cocoa/Foundation sobreescriben este método o bien proporcionan versiones algo más sofisticadas. Por ejemplo, NSString implementa también un método isEqualToString, especializado en comparar cadenas.

    • En nuestras propias clases deberíamos sobreescribir el isEqual ya que la versión de NSObject usa simplemente un == para comparar.

  • hash: debe calcular (cómo no) un hash para nuestro objeto. La implementación por defecto simplemente devuelve la dirección del objeto, de modo que en nuestras propias clases deberíamos sobreescribirlo si lo necesitamos. La mayoría de clases de Cocoa lo sobreescriben.

hasta iOS 7 hash era un método. En iOS 8 es una propiedad

Como especifica la documentación de Apple, si sobreescribimos isEqual también debemos hacer lo propio con hashsi queremos usar la clase en colecciones. En caso contrario podemos tener problemas, ya que dos objetos iguales deberían tener el mismo valor de hash.

  • description: debería devolver un NSString* con una descripción del objeto (al estilo toString de Java). Como en los métodos anteriores, deberíamos sobreescribirlo en nuestras propias clases ya que la implementación por defecto imprime simplemente el nombre de la clase y la dirección en memoria de la instancia.

Cadenas

Ya hemos usado múltiples veces NSString. La clase tiene numerosos métodos para manipulación de cadenas, búsqueda de subcadenas, conversión entre cadenas de C y NSString, etc. La clase es inmutable pero su subclase NSMutableString sí es mutable. Podéis consultar este tutorial para ver ejemplos de uso

Fechas

Otra clase básica es NSDate, para el manejo de fechas. Podéis ver ejemplos de su uso en este tutorial.

Colecciones

  • Todas las colecciones de Foundation vienen en una versión “inmutable” y otra “mutable”.

  • Cuando se añade un objeto a una colección mutable lo que se está añadiendo es una referencia, no una copia, por lo que modificar el objeto original modificará la colección.

    Wrappers de tipos primitivos

  • Las colecciones son conjuntos de objetos, por lo que directamente no pueden almacenar valores primitivos de C. Necesitaremos “empaquetar” estos tipos primitivos dentro de objetos usando wrappers.

  • NSNumber es un wrapper que puede empaquetar en forma de objeto cualquier tipo numérico de C. Además de para las colecciones, ciertos métodos de Cocoa requieren de datos numéricos como objetos en lugar de tipos primitivos.

  • Podemos definir un NSNumber precediendo un literal del símbolo @. Con una expresión debemos usar además paréntesis, por ejemplo

NSNumber *num = @7.25;
float flo = 3.5;
NSNumber *otro_num = @(flo);
  • Un NSNumber no es directamente un número por lo que no puede participar en operaciones aritméticas, etc. Pero sí podemos obtener el valor empaquetado dentro con los métodos intValue, floatValue, etc.

El compilador no chequea tipos al desempaquetar los valores, de modo que no dará error si llamamos por ejemplo a intValuepara un valor empaquetado como float. En este caso simplemente truncará el valor.

  • Por otro lado, no es posible añadir nil a una colección ya que significa “vacío”. Si queremos representar esto en una colección usaremos la clase NSNull. Es un singleton, y para obtener su única instancia se usa el método de clase null

id obj_nulo = [NSNull null];

Listas

  • La versión inmutable es NSArray y la mutable es su subclase NSMutableArray

  • Un NSArray puede contener objetos de distintas clases. Por otro lado, los NSMutableArray pueden cambiar no solo de contenido sino también de tamaño. Es decir, son más parecidos a las listas de Java o a los arrays de Python/Ruby… que a los arrays de C.

  • La manera más sencilla de inicializar un NSArray es con un literal

    NSArray *a = @[@1, @"hola"];

  • Para inicializar un NSMutableArray no podemos usar literales, sino un método de clase que actúa como una factoría:

//El método admite un número variable de argumentos, terminados en "nil"
NSMutableArray *mut = [NSMutableArray arrayWithObjects:
                              @1, @"Hola", nil];
  • Podemos obtener el número de elementos que tiene la lista con el método count. Este método sirve también para las otras colecciones.

  • Podemos añadir un elemento a un NSMutableArray con addObject. O insertarlo en una posición específica con insertObject:atIndex. El elemento que estuviera en esa posición y los siguientes se moverán una posición “a la derecha”.

[mut insertObject:@"adios" atIndex:1];
  • También podemos eliminar elementos, reemplazarlos, ordenarlos, filtrarlos,… se pueden ver ejemplos de uso en este tutorial.

Diccionarios

  • Un diccionario es un conjunto de pares (clave, valor). Las claves suelen ser NSString, pero se puede usar cualquier objeto que sea copiable (sea conforme a NSCopying) e implemente isEqual y hash.

  • `NSDictionary```es la versión inmutable yNSMutableDictionary` la mutable.

  • Podemos crear un NSDictionary con un literal. Se usan las llaves como delimitador, la clave se separa del valor por ``:```y las parejas clave-valor por comas

NSDictionary meses = @{
       @"Enero" : @31,
       @"Febrero" : @28,
       @"Marzo" : @30
};
  • Podemos obtener un valor a partir de la clave usando notación de array meses[@"Enero"]

    • Al igual que con los NSArray, para crear la versión mutable necesitamos un método factoría. Hay varios, por ejemplo podemos crearlo a partir de dos arrays, uno para los valores y otro para las claves

NSArray *nombres = @[@"Enero", @"Febrero", @"Marzo"];
NSArray *dias = @[@31, @28, @30];

NSMutableDictionary *meses = [NSMutableDictionary dictionaryWithObjects:dias forKeys:nombres];
  • Para añadir un elemento a un diccionario mutable podemos usar la notación de array o bien usar el método setObject:forKey

meses[@"Septiembre" ] = @30;
[meses setObject:@31 forKey:@"Diciembre"];
  • Podemos ver más ejemplos de uso de diccionarios en este tutorial.

Conjuntos

  • Un conjunto es una colección no ordenada de elementos distintos. Al igual que en el resto de colecciones, tenemos la versión inmutable NSSet y la mutable NSMutableSet.

  • No se pueden usar literales para inicializar conjuntos, pero sí hay varios métodos factoría, por ejemplo setWithObjects

    NSSet *conj = [NSSet setWithObjects:@1, @"Hola", nil];

    • Podemos comprobar si un objeto está en una colección con containsObject. Aunque esto también se puede hacer con NSArray los conjuntos lo implementan de modo mucho más eficiente.

  • Podemos añadir un objeto con addObject y eliminarlo con removeObject

  • Podemos ejecutar otras operaciones típicas de conjuntos, como la unión, la intersección, etc. Para más ejemplos de uso de conjuntos, consultar este tutorial.

Recorrer una colección

  • La forma más simple de recorrer una colección es con la denominada fast enumeration, que consiste en un for-in al estilo Java 5.

for(id obj in coleccion) {
    NSLog(@"Obtenido el objeto %@", obj);
}
  • Si el tipo de objetos de la colección es uniforme y lo conocemos, podemos especificarlo, el código quedará más claro

for(NSString *cad in coleccion) {
    NSLog(@"Obtenida la cadena %@", cad);
}
  • El fast enumeration aplicado a diccionarios efectúa una iteración por las claves, pero a partir de ellas recuperar los valores es muy sencillo,como ya hemos visto

    for (id clave in diccionario) {
        NSLog(@"(%@, %@)", clave, [diccionario objectForKey: clave]);
    }
  • Además de la fast enumeration se pueden usar enumerators, que son como los iteradores de Java, pero al igual que en este lenguaje el código resulta más complejo.

Si mientras estamos recorriendo una colección mutable (tanto con for-in como con un enumerador) tratamos de modificarla, obtendremos un error en tiempo de ejecución.

Apéndice: Git y Xcode

Operaciones básicas de Git desde Xcode

  • Al crear el proyecto marcando la opción de usar un repositorio Git, automáticamente se ha inicializado el repositorio y hecho el commit de los archivos iniciales de la plantilla que hayamos elegido.

  • Cada vez que modifiquemos uno de los archivos, Xcode nos lo indicará en el navegador del proyecto con una M. Si añadimos alguno aparecerá una A.

  • Para hacer un commit, Source Control > Commit.... En el cuadro de diálogo podremos revisar los archivos cambiados y escribir el mensaje de commit

  • Para anular todos los cambios, y volver al último commit Source Control > Discard all changes...

  • Podemos trabajar con ramas desde la primera opción del menú Source Control, que pone el nombre de la rama actual (por defecto “master”) y nos permite crear una nueva, cambiar de rama, hacer un merge, …

https://developer.apple.com/library/ios/documentation/general/conceptual/devpedia-cocoacore/

Referencias

Algunas referencias para aprender Objective-C y de introducción básica a la plataforma iOS

Recursos generales

  • iOS Dev Center de Apple, con todos los recursos (guías, referencias, ejemplos de código, …) que Apple ofrece a los desarrolladores. Es necesario registrarse (gratuitamente) para ver algunos recursos (por ejemplo, los videos de las sesiones de la WWDC, muy recomendables).

Guías de Apple

Tutoriales en la web

Libros

Disponibles en versión electrónica desde las IPs de la UA a través del servicio Safari Books Online. Aunque esta plataforma ofrece decenas de libros sobre Objective-C e iOS, son muy recomendables los siguientes:

Ejercicios de introducción a iOS

Mostrar imagen además de respuesta en modo texto

En lugar de mostrar solo el texto de la respuesta, también vamos a mostrar una imagen que la “ilustre”. Tendremos dos imágenes: una para cuando la respuesta es positiva y otra para cuando es negativa.

Parte 1: modificación del modelo

  • Primero habrá que modificar el modelo para que en lugar de almacenar simplemente los textos de las respuestas para cada una se almacene el texto y además si la respuesta es positiva/negativa. Crearemos la clase Respuesta

  • Despúes añadirle a la clase Respuesta un constructor initWithTexto:andTipo: para poderle pasar el texto y si es positiva/negativa. El constructor se usaría de este modo:

Respuesta *r1 = [[Respuesta alloc] initWithTexto:@"NOOO!!" andTipo:NO];
  • Para instanciar el NSMutableArray de respuestas lo más simple es usar el mismo método que hasta ahora, el método de clase arrayWithObjects, pero ahora le pasaremos instancias de la clase Respuesta en lugar de cadenas de Foundation. Es decir, aunque quede un código un poco “sucio”, para simplificar, creamos varias variables de tipo Respuesta * y luego las añadimos al NSMutableArray.

Parte 2: interfaz gráfico

  • Crear una “Image view” en el interfaz de usuario, usando la “Object Library” (panel inferior derecho de Xcode)

  • Crear un outlet que asocie esta “image view” con una propiedad en el ViewController.h. Podéis llamar a esta propiedad como queráis, por ejemplo “imagen”.

  • Añadir las imágenes que están en las plantillas de la sesión al “images.xcassets”. Darles un nombre corto para referirnos luego a ellas en el código.

  • En el controller, dentro del método botonPulsado, además de mostrar la respuesta en la etiqueta, hay que actualizar la “image view”. Recordar que se puede cargar una imagen con imageNamed:. Lo que tenemos que cambiar de la “image view” es la propiedad image

'//suponiendo que el outlet que se refiere a la "image view" se llama "imagen"
self.imagen.image = [UIImage imageNamed:@"nombre_de_imagen"]

Last updated