iOS desde cero con Swift: primeros pasos con UIKit
Spanish (Español) translation by Elías Nicolás (you can also view the original English article)
UIKit es el marco que usará más a menudo cuando desarrolle aplicaciones iOS. Define
los componentes principales de una aplicación iOS, desde etiquetas y
botones hasta vistas de tabla y controladores de navegación. En
este artículo, no solo comenzaremos nuestra exploración del marco
UIKit, sino que también exploraremos los aspectos internos de un
proyecto iOS y los componentes básicos de las aplicaciones iOS.
¿Qué es el marco UIKit?
Si bien el framework de Foundation define clases, protocolos y funciones para el desarrollo de iOS y OS X, el framework UIKit está exclusivamente orientado al desarrollo de iOS. Es el equivalente de Application Kit o AppKit framework para el desarrollo de OS X.
Al igual que Foundation,
UIKit define clases, protocolos, funciones, tipos de datos y constantes. También
agrega funcionalidad adicional a varias clases de Foundation, como
NSObject, NSString y NSValue mediante el uso de categorías
Objective-C.
Las categorías Objective-C son una forma conveniente de agregar métodos adicionales a las clases existentes sin la necesidad de subclases. Son similares a las extensiones de Swift. Lee este tutorial de Aaron Crabtree si quieres aprender más sobre las categorías de Objective-C.
En lugar de explorar las clases clave de UIKit, como hicimos con el framework de Foundation, vamos a crear y recorrer un nuevo proyecto de iOS, explorando las clases que encontramos. Al tomar este enfoque, rápidamente quedará claro en qué contexto se usa una clase, cómo cada clase se ajusta al esquema más amplio de una aplicación de iOS, y qué papel desempeña.
Un nuevo comienzo
Inicie Xcode y cree un nuevo proyecto seleccionando New > Project... en el menú File. En la sección de iOS de la izquierda, selecciona la categoría Application. De la lista de plantillas de proyecto, elija la plantilla Application de vista única.
La plantilla Single View Application contiene los componentes básicos de una aplicación de iOS, lo que lo convierte en un buen lugar para comenzar nuestro viaje.



Nombre el proyecto FirstSteps e ingrese el nombre e identificador de la organización. Establezca Language a Swift y configure Devices a iPhone. Deje las
casillas de verificación en la parte inferior sin marcar.



Dile
a Xcode dónde quieres guardar el nuevo proyecto y asegúrate de poner el
proyecto bajo control de versión marcando la casilla de verificación
etiquetada Create Git repository on My Mac. Revise este artículo para
obtener más información sobre el control de versiones y sus
beneficios.



Guardar el proyecto
Archivos y carpetasHemos aprendido bastantes cosas nuevas desde la última vez que creamos un proyecto de iOS desde cero, por lo que es una buena idea explorar los diversos archivos y carpetas de nuestro nuevo proyecto para ver si suenan.
En Project Navigator, debería ver dos carpetas en la raíz del proyecto:
- Products
- una carpeta con el nombre de su proyecto, FirstSteps en este ejemplo
Echemos un vistazo al contenido de cada una de estas carpetas.



Products
La carpeta Products contiene actualmente un elemento. Lleva el nombre del proyecto y tiene una extensión .app. La carpeta Products contiene la aplicación o aplicaciones creadas por el proyecto después de la compilación del código fuente.
¿Has notado que FirstSteps.app está resaltado en rojo? Cuando Xcode no puede ubicar un archivo, resalta el archivo en rojo. No te preocupes, sin embargo. Debido a que el proyecto aún no se ha compilado, Xcode aún no ha creado el producto.
Carpeta del proyecto
La mayor parte de su tiempo se gasta en la carpeta del proyecto, que actualmente contiene seis archivos. Los primeros dos archivos, AppDelegate.swift y ViewController.swift, son archivos fuente. Estos archivos contienen el código fuente de la aplicación.
Main.storyboard
contiene la interfaz de usuario de la aplicación. Ya hemos trabajado con
guiones gráficos anteriormente en esta serie. Tenga en cuenta que hay
un segundo storyboard, LaunchScreen.storyboard. Este storyboard es
utilizado por el sistema operativo cuando se lanza la aplicación. En
lugar de mostrar una vista vacía, el sistema operativo usa este storyboard para crear dinámicamente una imagen de inicio, que se muestra al
usuario cuando se carga la aplicación.
Info.plist,
comúnmente conocido como el archivo "info-punto-plist" de un proyecto,
es una lista de propiedades que contiene varias configuraciones. La
mayoría de estos ajustes también se pueden modificar seleccionando el
proyecto en el Project Navigator, eligiendo el objetivo en la lista
de Targets y abriendo las pestañas General, Capabilities, e
Info.
Assets.xcassets es un tipo especial de carpeta para almacenar los activos de su proyecto, como las imágenes.Componentes de la aplicación
Componentes de la aplicación
Ahora que sabemos para qué sirven los diferentes archivos y carpetas de nuestro proyecto, es el momento de explorar los diferentes componentes de una aplicación de iOS. A medida que continuamos nuestro viaje, encontraremos varias clases que pertenecen a UIKit. Cada clase que pertenece al marco UIKit comienza con la interfaz de usuario del prefijo UI. Recuerde que las clases de Foundation tienen el prefijo NS.
El patrón Model-View-Controller
Antes de comenzar a explorar el marco UIKit, quiero hablar sobre el patrón Model-View-Controller (MVC). El patrón MVC es uno de los patrones más extendidos en la programación orientada a objetos. Promueve la reutilización del código y tiene vínculos estrechos con el concepto de separación de responsabilidades o preocupaciones. Uno de los principales objetivos del patrón MVC es la separación de la lógica de negocios de una aplicación de la capa de presentación.
Cocoa Touch adopta el patrón MVC, lo que significa que es importante entender qué es y cómo funciona. En otras palabras, al comprender el patrón MVC, será mucho más fácil comprender cómo funcionan los diferentes componentes de una aplicación iOS.
En el patrón MVC, la capa del modelo tiene el control de la lógica comercial de una aplicación. La interacción con una base de datos, por ejemplo, es responsabilidad de la capa del modelo. La capa de vista presenta los datos que la capa de modelo gestiona para el usuario. La capa de vista administra la interfaz de usuario y la entrada del usuario.
El controlador es el pegamento entre la capa del modelo y la capa de visualización. Si bien la capa del modelo y la capa de vista no conocen la existencia de la otra, el controlador conoce ambas.
Debido a que el controlador conoce el modelo y la vista, a menudo es la pieza menos reutilizable de una aplicación. Cuanto menos sepa un objeto sobre su entorno y los objetos con los que interactúa, más fácil será reutilizarlo.
UIApplication
Aunque
la clase UIApplication es un componente clave de cada aplicación iOS,
no interactuarás con ella muy a menudo y rara vez, o nunca, sentirás la
necesidad de subclase de UIApplication.
Cuando se inicia una
aplicación, se crea un singleton de esta clase. ¿Recuerdas qué es un
objeto singleton? Significa que solo se crea una instancia de objeto de
la clase UIApplication durante la vigencia de una aplicación.
La
instancia de UIApplication es el punto de entrada para la interacción
del usuario y distribuye eventos a los objetos de destino apropiados. El
significado exacto de esto se aclarará en unos minutos cuando echemos
un vistazo a los controladores de vista.
En las aplicaciones iOS, la
instancia UIApplication tiene un objeto delegado asociado. Cada
vez que crees un proyecto de iOS usando una de las plantillas
proporcionadas, Xcode creará una clase de delegado de aplicaciones para
ti. Eche un vistazo a los nombres de los archivos fuente en la carpeta
del proyecto en Project Navigator. El primer archivo se llama
AppDelegate.swift.
La instancia de esta clase es el delegado del
singleton UIApplication. Antes de echar un vistazo más de cerca a la
clase AppDelegate, debemos entender cuál es el patrón delegado.
Ole
Begemann escribió un excelente artículo sobre la secuencia de
lanzamiento de una aplicación típica de iOS. En
su artículo, Ole habla sobre los diversos componentes involucrados y su
rol durante la secuencia de lanzamiento de la aplicación. Recomiendo
leer este artículo si quieres entender mejor el rol de la clase
UIApplication.
El patrón de delegado
El patrón de delegados se usa ampliamente en Cocoa y Cocoa Touch. En un artículo futuro de esta serie, en el que exploramos los pormenores de las vistas de tabla, descubrirá que las vistas de tabla dependen en gran medida del patrón de delegado (y fuente de datos).
Al igual que el patrón MVC, la delegación es común en la programación orientada a objetos. El patrón delegado en Cocoa Touch, sin embargo, es ligeramente diferente, ya que utiliza un protocolo delegado para definir el comportamiento del objeto delegado.
Avancemos y miremos las vistas de la tabla. Si ha pasado
algún tiempo con un iPhone o iPad, la clase UITableView debería serle
familiar. Presenta una lista ordenada de datos para el usuario y hace
muy bien este trabajo.
¿Cómo sabe una vista de tabla qué hacer cuando se
toca una fila? ¿Este comportamiento está incluido en la clase
UITableView? Ciertamente no, porque este comportamiento varía de una
aplicación a otra. Si tuviéramos que incluir este comportamiento en la
clase UITableView, no sería muy reutilizable.
La vista de tabla
externaliza esta responsabilidad a un objeto delegado. Dicho de otra
manera, delega esta tarea en otro objeto, un objeto delegado. Tómese un
momento para inspeccionar la referencia de clase de la clase
UITableView. Tiene dos propiedades llamadas dataSource y delegate. La
vista de tabla notifica delegate cuando el usuario toca una fila. Es
responsabilidad del objeto delegado responder a ese evento táctil.
La fuente de datos de la vista de tabla es similar. La principal diferencia es que la vista de tabla le pide al objeto de fuente de datos algo, los datos que necesita para mostrar.
Los
objetos de delegado y fuente de datos, como los objetos delegate y
dataSource de la vista de tabla, son casi siempre clases personalizadas. En
la mayoría de los casos, le corresponde al desarrollador crear e
implementar estas clases, porque su implementación es específica para
cada aplicación.
El delegado de la aplicación
Ahora que sabemos qué es la
delegación, es hora de explorar la clase de AppDelegate que Xcode creó
para nosotros. En el lanzamiento de la aplicación, la aplicación crea
una instancia de la clase AppDelegate. Esta
instancia de AppDelegate se configura como el delegado de la instancia
de UIApplication que el sistema operativo creó para su aplicación. Nunca
crea una instancia explícita de un objeto delegado de la
aplicación.
Abra AppDelegate.swift para examinar la implementación de la
clase AppDelegate. Ignorando
los comentarios en la parte superior, la primera línea importa el marco
UIKit para que podamos trabajar con sus clases y protocolos.
1 |
import UIKit |
En la siguiente línea, vemos algo que aún no hemos cubierto, un
atributo. Los atributos en Swift comienzan con un símbolo @ y se pueden
ver como instrucciones para el compilador. El
atributo @UIApplicationMain le dice al compilador que AppDelegate es la
clase que debe usarse como delegado de la aplicación. Eso es todo lo
que necesita saber sobre este atributo por ahora.
1 |
@UIApplicationMain |
La
próxima línea debería ser familiar. Este es el comienzo de la
declaración de la clase AppDelegate. Especifica el nombre de la clase y
la clase padre de la clase, UIResponder.
También le dice al compilador
que AppDelegate cumple con el protocolo UIApplicationDelegate. Esto no
es sorprendente, ya que sabemos que AppDelegate sirve como delegado de
la aplicación.
1 |
class AppDelegate: UIResponder, UIApplicationDelegate { |
2 |
...
|
3 |
}
|
La siguiente línea es una declaración de propiedad para la
propiedad window. Tenga en cuenta que la propiedad es una
variable de tipo UIWindow?. La clase UIWindow es una subclase de
UIView, la clase base para las vistas en iOS.
1 |
var window: UIWindow? |
La
parte más interesante de la interfaz de la clase AppDelegate es el
protocolo UIApplicationDelegate. Eche
un vistazo a la referencia del protocolo UIApplicationDelegate para
obtener una lista completa de los métodos que define el protocolo.
El
protocolo define docenas de métodos y los animo a explorar algunos de
ellos para tener una idea de las capacidades del protocolo. El método
que más nos interesa en este momento es la application(_:didFinishLaunchingWithOptions:).
Cuando
el objeto UIApplication ha terminado de preparar la aplicación para el
lanzamiento, notifica a su delegado, el objeto AppDelegate, que la
aplicación está a punto de iniciarse.
¿Por qué notifica al delegado de la
aplicación de este evento? La
instancia de UIApplication notifica a su delegado sobre este evento
para que tenga la oportunidad de prepararse para el lanzamiento de la
aplicación. La implementación de application(_:didFinishLaunchingWithOptions:) es bastante corta, como puede ver a
continuación.
1 |
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { |
2 |
// Override point for customization after application launch.
|
3 |
return true |
4 |
}
|
Proporciona una
referencia a la instancia de UIApplication y un diccionario de opciones. Puede ignorar el diccionario de opciones por el momento. Para
garantizar que el sistema operativo inicie la aplicación, devolvemos true.
Storyboard
El proyecto Xcode contiene otro archivo interesante, Main.storyboard. El storyboard define cómo se ve la interfaz de usuario de su aplicación. De forma predeterminada, el storyboard se llama Main.storyboard. Seleccione el storyboard para abrirlo.



El storyboard actualmente contiene una vista en el espacio de trabajo central. A la derecha de Project Navigator, puede ver una lista de elementos, que son los objetos que ve en la vista. El elemento superior, View Controller Scene, contiene un elemento secundario, View Controller.
El objeto View Controller también tiene una cantidad de elementos secundarios, pero hay uno que nos interesa especialmente, el objeto llamado View. Recuerde la discusión sobre el patrón MVC. Ahora puede ver el patrón MVC en acción. El modelo falta en este momento, pero tenemos una vista, el objeto View y un controlador, el objeto View Controller.
Cuando se inicia la aplicación, el storyboard se usa para crear la interfaz de usuario de la aplicación. El controlador de vista se instancia automáticamente y también lo hace la vista del controlador de vista. El controlador View controla el objeto View en el storyboard.
Espera un minuto. ¿Dónde puedo encontrar la clase del controlador de vista en el guión gráfico? ¿Cómo puedo cambiar su comportamiento para crear una aplicación única? Seleccione el objeto View Controller a la izquierda y abra el Identity Inspector a la derecha.



El Identity Inspector le
dice todo lo que necesita saber. En
la parte superior, en la sección Custom Class, puede ver el
nombre de la clase del controlador de vista, ViewController. ¿Has notado
que el archivo del que no hemos hablado todavía lleva el mismo nombre? Exploraremos este archivo en unos momentos.
El controlador de vista se crea una instancia para nosotros, porque es el controlador de vista inicial del storyboard. Esto se indica en el storyboard con la flecha que apunta a View Controller Scene.



UIViewController
Si abre
ViewController.swift, notará que la clase ViewController es una subclase
de UIViewController. Al igual que AppDelegate, la clase
UIViewController es una subclase de UIResponder. Los controladores de
vista, o subclases de los mismos, caen en la categoría de controlador
del patrón MVC. Como
su nombre lo indica, controlan una vista, una instancia de la clase
UIView, que pertenece a la categoría vista del patrón MVC.
Como veremos más adelante, un controlador de vista administra una vista y sus subvistas. Para hacer esto, el controlador de vista necesita saber sobre la vista. En otras palabras, necesita tener una referencia a la vista.
El controlador de vista en el storyboard tiene una referencia a la vista. Puede verificar esto seleccionando el controlador de vista en el storyboard y abriendo Connections Inspector a la derecha.



En Connections
Inspector, debería ver una sección llamada Outlets. El término de salida
es una palabra elegante para una propiedad que puede establecer en el
storyboard. Desplácese con el mouse sobre la view denominada outlet y
observe cómo se resalta la vista en el área de trabajo. Esa es la
conexión entre el view controller y view.
UIView
Aunque su
aplicación solo puede tener una instancia de UIWindow, puede tener
muchas vistas. La clase UIView es un componente importante del marco
UIKit porque muchas clases heredan de él, directa o
indirectamente.
Revise Main.storyboard seleccionándolo y eche un vistazo a la Object Library en la parte inferior del Inspector.



Explore la Object Library y arrastre una label y un button a la vista en el espacio de trabajo. No importa dónde los coloque en la vista, siempre y cuando estén en la vista del controlador de vista.



Observe que se han agregado dos objetos nuevos a la sección Objects a la izquierda. Tanto la etiqueta (UILabel) como el botón
(UIButton) heredan de UIView. ¿Ha notado que los objetos Label y
Button tienen una sangría leve en comparación con el objeto View? Esto
indica que los objetos Label y Button son subvistas del objeto View. Una vista puede tener una o más subvistas que administra.
Como mencioné
anteriormente, la clase UIView es un componente importante de UIKit. Una
vista administra un área o marco rectangular en la pantalla. Administra
los contenidos del área, las subvistas y cualquier interacción con los
contenidos de la vista. La clase UIView es una subclase de UIResponder. Aprenderá mucho más sobre las vistas en el transcurso de esta
serie.
Outlets
Echemos un vistazo a un ejemplo para ilustrar la relación entre el storyboard, la vista que contiene y el controlador de vista. Estos tres componentes son importantes y quiero asegurarme de que entiendas cómo funcionan juntos.
Hace unos momentos, agregó una etiqueta y un botón a la vista del controlador de vista. ¿Cómo sabe el controlador de vista sobre estos objetos? Por el momento, no aparecen en el Connections Inspector, pero podemos cambiar eso contándole al controlador de vista sobre ellos. Abra ViewController.swift y agregue una propiedad para la etiqueta y otra para el botón.
1 |
import UIKit |
2 |
|
3 |
class ViewController: UIViewController { |
4 |
|
5 |
@IBOutlet var myLabel: UILabel! |
6 |
@IBOutlet var myButton: UIButton! |
7 |
|
8 |
...
|
9 |
|
10 |
}
|
Al
agregar el atributo @IBOutlet a la declaración de propiedad, las
propiedades aparecen en el Connections Inspector en el storyboard y
eso es lo que queremos.
Regrese al guión gráfico, seleccione el objeto View Controller en View Controller Scene, y abra Connections Inspector a la derecha. Las nuevas propiedades ahora se enumeran en la lista de Outlets. Sin embargo, el controlador de vista aún no ha establecido la conexión entre las nuevas propiedades y los objetos en el storyboard.
Esto es
fácil de remediar. Arrastre desde el círculo vacío a la izquierda de la
salida myLabel hasta la etiqueta en el área de trabajo. Esto creará la
conexión. El controlador de vista ahora sabe acerca de la etiqueta. Repita este paso para el botón.



Aunque
podemos cambiar el texto de la etiqueta en el guión gráfico, hagámoslo
en el controlador de vista para ilustrar que el controlador de vista
tiene acceso a la etiqueta y al botón en el storyboard.
Abra
ViewController.swift y busque el método viewDidLoad(). Modifique el
método viewDidLoad() para reflejar la implementación a continuación. Los comentarios han sido omitidos para mayor claridad.
1 |
override func viewDidLoad() { |
2 |
super.viewDidLoad() |
3 |
|
4 |
myLabel.text = "This is an instance of a UILabel." |
5 |
}
|
Podemos enviar mensajes a la propiedad de etiqueta accediendo a la propiedad myLabel del controlador de vista. Podemos cambiar el texto de la etiqueta estableciendo la propiedad text de la etiqueta, usando un literal de cadena.
1 |
myLabel.text = "This is an instance of a UILabel." |
El método viewDidLoad() se invoca
automáticamente cuando el controlador de vista ha cargado su vista. La
palabra clave override indica que estamos anulando un método que está
definido por una clase más arriba en el árbol de herencia. La clase
UIViewController, la clase padre de la clase ViewController, implementa
este método.
También tenga en cuenta que invocamos viewDidLoad() en
super. ¿Qué es super? Al igual que self se refiere a la instancia
actual, super se refiere a la clase padre, UIViewController. En otras
palabras, invocamos el método viewDidLoad() en la superclase. Esto
a menudo es importante cuando se anula un método en una subclase,
porque la superclase puede estar llevando a cabo tareas importantes en
su propia implementación y no queremos romper nada.
Ejecute su aplicación
en el simulador haciendo clic en el botón Run en la parte superior
izquierda. Tenga en cuenta que el texto de la etiqueta se ha
actualizado. No se preocupe por la posición de la etiqueta y el botón. Eso es algo que solucionaremos en el próximo
tutorial.
Actions
Hemos explorado muchas cosas nuevas en este artículo. Quiero terminar esta entrega hablando de actions. Al igual que los puntos de venta, las acciones no son más que métodos a los que puede acceder en el storyboard.
Veamos cómo funciona esto. Abra
ViewController.swift y agregue el siguiente método debajo del método
viewDidLoad().
1 |
@IBAction func changeColor(sender: UIButton) { |
2 |
print(sender.classForCoder) |
3 |
print(sender.superclass) |
4 |
|
5 |
let r = CGFloat(arc4random() % 255) |
6 |
let g = CGFloat(arc4random() % 255) |
7 |
let b = CGFloat(arc4random() % 255) |
8 |
|
9 |
let color = UIColor(red: (r/255.0), green: (g/255.0), blue: (b/255.0), alpha: 1.0) |
10 |
|
11 |
view.backgroundColor = color |
12 |
}
|
No
se deje confundir por el atributo @IBAction. Este atributo indica que el
método es una acción y, por lo tanto, accesible en el storyboard. Si
echamos un vistazo más de cerca a la acción changeColor(_:), podemos
ver que se necesita un argumento de tipo UIButton.
Como el nombre del argumento implica, el argumento del método o acción es el objeto que envió el mensaje al controlador de vista. Explicaré esto con más detalle en solo un momento.
Vuelva a visitar el storyboard, seleccione el objeto View Controller en View Controller Scene y abra Connections Inspector. Apareció una nueva sección en el Connections Inspector, Received Actions, y la acción que acabamos de agregar se detalla en esta sección.



Arrastre desde el círculo vacío a la izquierda de la acción hasta el botón en el espacio de trabajo. Aparecerá un menú emergente con una lista de opciones. La lista contiene todos los eventos posibles a los que el botón puede responder. El que nos interesa es Touch Up Inside. Este evento se desencadena cuando un usuario toca el botón y levanta el dedo dentro de los límites del botón.



Ejecute su aplicación una vez más
y toque el botón. La vista del controlador de vista debe cambiar de
color cada vez que toca el botón. Agregamos dos instrucciones de
impresión a la acción changeColor(_:). Veamos cómo se ve la salida
cuando toca el botón.
1 |
UIButton
|
2 |
Optional(UIControl) |
La primera línea
muestra la clase del remitente, una instancia de UIButton. Esto
demuestra que es el botón el que activa este método en el controlador de
vista. Está enviando un mensaje de changeColor(_:) al controlador de
vista.
La segunda línea muestra la superclase del remitente. Recuerde que
no todas las clases tienen una superclase. Esa es la razón por la que
recibimos un opcional. El resultado nos dice que la clase padre de
UIButton es UIControl.
El método en sí es bastante simple. Generamos
tres enteros aleatorios entre 0 y 255, pasamos estos valores a init(red:green:blue:alpha:) para generar un color aleatorio y
actualizamos el color de fondo de la vista del controlador de vista con
el color generado aleatoriamente. Tenga en cuenta que view hace
referencia a la vista que administra el controlador de
vista.
Conclusión
En este artículo, exploramos algunas clases del marco UIKit y examinamos de cerca los diversos componentes de una aplicación iOS. Exploraremos y trabajaremos con el marco de UIKit con más detalle en el resto de esta serie. Si no comprende completamente los diversos conceptos y patrones, entonces estoy seguro de que lo hará a medida que avance la serie.
Si tiene
preguntas o comentarios, puede dejarlos en los comentarios a
continuación o comunicarse conmigo en Twitter.



