Advertisement
  1. Code
  2. Mobile Development
  3. iOS Development

iOS desde cero con Swift: controladores de navegación y jerarquías de controladores de vista

Scroll to top
Read Time: 25 min
This post is part of a series called iOS From Scratch With Swift.
iOS From Scratch With Swift: Table View Basics
iOS From Scratch With Swift: Exploring Tab Bar Controllers

() translation by (you can also view the original English article)

En iOS, los controladores de navegación son una de las principales herramientas para presentar múltiples pantallas de contenido. Este artículo le enseña a usar los controladores de navegación mediante la creación de una aplicación para explorar los libros de una biblioteca.

Introduccion

En el tutorial anterior, aprendió que la clase de vista de tabla de UIKit es excelente para presentar datos tabulares o columnares. Sin embargo, cuando el contenido debe distribuirse en varias pantallas, un controlador de navegación suele ser la herramienta de elección. La clase UINavigationController implementa este tipo de funcionalidad.

Al igual que cualquier otra subclase UIViewController, un controlador de navegación administra una vista, una instancia de la clase UIView. La vista del controlador de navegación administra varias subvistas, incluida una barra de navegación en la parte superior, una vista que contiene contenido personalizado y una barra de herramientas opcional en la parte inferior. Lo que hace que un controlador de navegación sea especial es que crea y administra una jerarquía de controladores de vista, a menudo denominada navigation stack.

En este artículo, creamos una nueva aplicación iOS para familiarizarnos con la clase UINavigationController. Aprenderá que la combinación de un controlador de navegación y una pila de controladores de vista (tabla) es una solución elegante y poderosa para presentar conjuntos de datos anidados.

Además de UINavigationController, también encontrará UITableViewController en esta guía de aprendizaje, otra subclase de UIViewController. UITableViewController administra una instancia de UITableView en lugar de una instancia de UIView. Los controladores de vista de tabla adoptan automáticamente los protocolos UITableViewDataSource y UITableViewDelegate y eso nos va a ahorrar algo de tiempo.

Otro proyecto

La aplicación que estamos por crear se llama Library. Con esta aplicación, los usuarios pueden navegar por una lista de autores y ver los libros que han escrito. La lista de autores se presenta en una vista de tabla.

Si el usuario toca el nombre de un autor, una lista de libros escritos por ese autor se anima a la vista. De forma similar, cuando el usuario selecciona un título de la lista de libros, otra vista se anima a la vista, mostrando una imagen de la portada del libro. Vamos a crear un nuevo proyecto de Xcode para que podamos comenzar.

Creando el Proyecto

Abra Xcode, cree un nuevo proyecto seleccionando New > Project... en el menú File y seleccione la plantilla Single View Application en la lista de Plantillas iOS > Application .

Choosing the Project TemplateChoosing the Project TemplateChoosing the Project Template

Nombre el proyecto Library y asigne un nombre e identificador de la organización. Establezca Language a Swift y Devices a iPhone. Dile a Xcode dónde quieres guardar el proyecto y haz clic en Create.

Configuring the ProjectConfiguring the ProjectConfiguring the Project

La plantilla Single View Application contiene una clase de delegado de aplicaciones, AppDelegate, un guión gráfico, Main.storyboard y una subclase UIViewController, ViewController. Abra AppDelegate.swift y eche un vistazo a la implementación de la application(_:didFinishLaunchingWithOptions:). Su implementación es corta y debería ser familiar por ahora.

1
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
2
    return true
3
}

Agregar recursos

Los archivos fuente de este tutorial incluyen los datos que usaremos. Puede encontrarlos en la carpeta llamada Resources. Incluye una lista de propiedades, Books.plist, que contiene información sobre los autores, los libros que han escrito, cierta información sobre cada libro y una imagen para cada libro incluido en la lista de propiedades.

Arrastre la carpeta Resources a su proyecto para agregarlos al proyecto. Xcode le mostrará algunas opciones cuando agrega la carpeta al proyecto. Asegúrese de marcar la casilla Copy items if needed y no olvide agregar los archivos al target de Library.

Add Resources to ProjectAdd Resources to ProjectAdd Resources to Project
Copy Items Into Destination Folder of GroupCopy Items Into Destination Folder of GroupCopy Items Into Destination Folder of Group

Listas de propiedades

Antes de continuar, quiero tomarme un momento para hablar sobre las listas de propiedades y lo que son. Una lista de propiedades no es más que una representación de un gráfico de objetos. Como vimos anteriormente en esta serie, un gráfico de objetos es un grupo de objetos que forma una red a través de las conexiones o referencias que comparten entre sí.

Es fácil leer y escribir listas de propiedades desde y hacia el disco, lo que las hace ideales para almacenar pequeñas cantidades de datos. Al trabajar con listas de propiedades, también es importante recordar que solo ciertos tipos de datos se pueden almacenar en listas de propiedades, como cadenas, números, fechas, matrices, diccionarios y datos binarios.

Xcode hace que buscar listas de propiedades sea muy fácil. Seleccione Books.plist de la carpeta Resources que agregó al proyecto y explore sus contenidos usando el editor de listas de propiedades incorporado de Xcode. Esta será una herramienta útil más adelante en este artículo cuando comencemos a trabajar con los contenidos de Books.plist.

Browsing a Property List in XcodeBrowsing a Property List in XcodeBrowsing a Property List in Xcode

Subclases de UITableViewController

Antes de que podamos comenzar a utilizar los datos almacenados en Books.plist, primero debemos establecer algunas bases. Esto incluye la creación de un controlador de vista que administre una vista de tabla y que muestre los autores enumerados en la lista de propiedades.

En el artículo anterior, creamos una subclase UIViewController y agregamos una vista de tabla a la vista del controlador de vista para presentar datos al usuario. En este tutorial, tomamos un atajo subclasificando UITableViewController.

Comience eliminando ViewController.swift de su proyecto. Cree una nueva clase seleccionando New > File... en el menú File. Seleccione la plantilla Cocoa Touch Class en la lista de Plantillas iOS > Source.

Create a New Cocoa Touch ClassCreate a New Cocoa Touch ClassCreate a New Cocoa Touch Class

Denomine la nueva clase AuthorsViewController y conviértala en una subclase de UITableViewController. No es necesario marcar la casilla de verificación Also create XIB file for user interface, porque usaremos el guión gráfico para crear la interfaz de usuario de la aplicación.

Configure the New Cocoa Touch ClassConfigure the New Cocoa Touch ClassConfigure the New Cocoa Touch Class

Abra Main.storyboard para reemplazar el controlador de vista en el storyboard con un controlador de vista de tabla. Seleccione el controlador de vista en el storyboard, presione la tecla Eliminar y arrastre una instancia de UITableViewController desde la Object Library a la derecha. Seleccione el nuevo controlador de vista, abra el Identity Inspector a la derecha y establezca su clase en AuthorsViewController.

Adding a Table View ControllerAdding a Table View ControllerAdding a Table View Controller

En el artículo anterior, hicimos uso de células prototipo para poblar la vista de tabla. En este tutorial, te mostraré un enfoque alternativo. Seleccione el objeto de vista de tabla en el área de trabajo o desde la lista de objetos a la izquierda, abra el Attributes Inspector a la derecha y configure las Prototype Cells en 0.

Remove Prototype CellsRemove Prototype CellsRemove Prototype Cells

Cada storyboard necesita un controlador de vista inicial. Este es el controlador de vista que se crea una instancia cuando se carga el storyboard. Podemos marcar el controlador de visualización de autores como el controlador de vista inicial seleccionando el objeto Authors View Controller a la izquierda, abriendo el Attributes Inspector a la derecha y marcando la casilla de verificación Is Initial View Controller.

Poblar la vista de tabla

Abre AuthorsViewController.swift e inspecciona el contenido del archivo. Debido a que AuthorsViewController es una subclase de UITableViewController, AuthorsViewController ya se ajusta a los protocolos UITableViewDataSource y UITableViewDelegate.

Antes de que podamos mostrar datos en la vista de tabla, necesitamos datos para mostrar. Como mencioné anteriormente, los datos contenidos en Books.plist sirven como fuente de datos de la vista de tabla. Para usar esta información, primero debemos cargarla en un objeto, una matriz para ser precisos.

Declaramos una propiedad variable authors y establecemos su valor inicial en una matriz vacía de tipo [AnyObject]. Recuerde que el tipo AnyObject puede representar cualquier clase o estructura.

El método viewDidLoad() del controlador de vista es un buen lugar para cargar los datos de Books.plist en la propiedad authors del controlador de vista. Hacemos esto invocando el inicializador init(contentsOfFile:) de la clase NSArray. Echamos el objeto resultante a una instancia de tipo [AnyObject].

1
authors = NSArray(contentsOfFile: path) as! [AnyObject]

El método acepta una ruta de archivo, lo que significa que tenemos que averiguar cuál es la ruta del archivo de Books.plist. El archivo, Books.plist, se encuentra en el paquete de la aplicación, que es una palabra elegante para el directorio que contiene el ejecutable de la aplicación y los recursos de la aplicación, como imágenes y sonidos.

Para obtener la ruta del archivo de Books.plist, primero necesitamos una referencia al paquete principal de la aplicación llamando a mainBundle() en la clase NSBundle. El siguiente paso es solicitar el paquete de la aplicación para la ruta de uno de sus recursos, Books.plist. Invocamos pathForResource(_:ofType:) en el paquete principal de la aplicación, pasando el nombre y el tipo (extensión) del archivo que nos interesa. Almacenamos la ruta del archivo en una constante, filePath.

1
let filePath = NSBundle.mainBundle().pathForResource("Books", ofType: "plist")

Como es posible que solicitemos un recurso que no está presente en el paquete de la aplicación, pathForResource(_:ofType:) devuelve un recurso opcional. Como regla general, si un método puede devolver nil, se debe usar un opcional. La constante filePath es de tipo String?. Para desenvolver de forma segura el elemento opcional, utilizamos el enlace opcional, que hemos discutido anteriormente en esta serie.

Si unimos las dos piezas, terminamos con la siguiente implementación de viewDidLoad(). También agregué una declaración de impresión para imprimir los contenidos de la propiedad authors a la consola. Esto nos permite echar un vistazo a sus contenidos.

1
override func viewDidLoad() {
2
    super.viewDidLoad()
3
    
4
    let filePath = NSBundle.mainBundle().pathForResource("Books", ofType: "plist")
5
    
6
    if let path = filePath {
7
        authors = NSArray(contentsOfFile: path) as! [AnyObject]
8
        print(authors)
9
    }
10
}

Si ha leído el artículo anterior de esta serie, llenar la vista de tabla debería ser sencillo. Como la vista de tabla contiene solo una sección, la implementación de numberOfSectionsInTableView(_:) es sencilla. AuthorsViewController hereda de UITableViewController, que ya se ajusta e implementa el protocolo UITableViewDataSource. Es por eso que debemos usar la palabra clave override. Estamos anulando un método implementado por la clase principal.

1
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
2
    return 1
3
}

El número de filas en la única sección de la vista de tabla es igual al número de autores en la matriz authors, de modo que todo lo que tenemos que hacer es contar los elementos de la matriz.

1
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
2
    return authors.count
3
}

La implementación de tableView(_:cellForRowAtIndexPath:) es similar a la que vimos en el artículo anterior. La principal diferencia es cómo buscamos los datos que mostramos en la celda de la vista de tabla.

La matriz de autores contiene una lista ordenada de diccionarios, con cada diccionario que contiene dos pares clave-valor. El objeto para la clave llamada Author es del tipo String,mientras que el objeto para la clave Books es una matriz de diccionarios con cada diccionario que representa un libro escrito por el autor. Abra Books.plist en Xcode para inspeccionar la estructura de la fuente de datos si esto no está del todo claro.

Antes de implementar tableView(_:cellForRowAtIndexPath:), tenemos que encargarnos de dos cosas. Primero, declaramos una constante para el identificador de reutilización de celda que vamos a usar.

1
import UIKit
2
3
class AuthorsViewController: UITableViewController {
4
5
    let CellIdentifier = "Cell Identifier"
6
    
7
    var authors = [AnyObject]()
8
    
9
    ...
10
11
}

En segundo lugar, llamamos registerClass(_:forCellReuseIdentifier:) en la vista de tabla, pasando en UITableViewCell.classForCoder() y el identificador de reutilización de celda. Invocamos este método en viewDidLoad() para asegurarnos de que se llame solo una vez.

1
override func viewDidLoad() {
2
    super.viewDidLoad()
3
    
4
    let filePath = NSBundle.mainBundle().pathForResource("Books", ofType: "plist")
5
    
6
    if let path = filePath {
7
        authors = NSArray(contentsOfFile: path) as! [AnyObject]
8
        print(authors)
9
    }
10
    
11
    tableView.registerClass(UITableViewCell.classForCoder(), forCellReuseIdentifier: CellIdentifier)
12
}

Con lo anterior en su lugar, la implementación de tableView(_:cellForRowAtIndexPath:) se vuelve bastante corta.

1
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
2
    // Dequeue Resuable Cell

3
    let cell = tableView.dequeueReusableCellWithIdentifier(CellIdentifier, forIndexPath: indexPath)
4
    
5
    if let author = authors[indexPath.row] as? [String: AnyObject], let name = author["Author"] as? String {
6
        // Configure Cell

7
        cell.textLabel?.text = name
8
    }
9
    
10
    return cell;
11
}

Tenga en cuenta que encadenamos enlaces opcionales con una coma. Este es un enfoque conveniente para evitar declaraciones if anidadas. Pedimos a authors el elemento en indexPath.row y lo bajamos como [String: AnyObject]. Debido a que necesitamos el nombre del autor, pedimos al author el valor de la clave "Author", bajando el resultado a String.

Agregar un controlador de navegación

Agregar un controlador de navegación es fácil usando un storyboard. Sin embargo, antes de agregar un controlador de navegación, es importante entender cómo funcionan los controladores de navegación en iOS.

Al igual que cualquier otra subclase UIViewController, un controlador de navegación administra una instancia de UIView. La vista del controlador de navegación administra varias subvistas, incluida una barra de navegación en la parte superior, una vista que contiene contenido personalizado y una barra de herramientas opcional en la parte inferior. Lo que hace que un controlador de navegación sea único es que administra una pila de controladores de visualización.

Navigation StackNavigation StackNavigation Stack

El término stack casi se puede tomar literalmente. Cuando se inicializa un controlador de navegación, el controlador de navegación recibe un controlador de vista raíz. El controlador de vista raíz es el controlador de vista en la parte inferior de navigation stack.

Al presionar otro controlador de vista en navigation stack, la vista del controlador de vista raíz se reemplaza con la vista del nuevo controlador de vista. Al trabajar con controladores de navegación, la vista visible es siempre la vista del controlador de vista superior de navigation stack.

Cuando un controlador de vista se elimina o extrae de la navigation stack, la vista del controlador de vista debajo de esta se vuelve a ver. Al presionar y abrir los controladores de vista hacia y desde la pila de navegación del controlador de navegación, se crea una jerarquía de vistas y, como resultado, se puede presentar un conjunto de datos anidados al usuario. Veamos cómo funciona todo esto de empujar y hacer estallar en la práctica.

Revise el storyboard del proyecto (Main.storyboard) y seleccione el controlador de vista. Para agregar un controlador de navegación a la mezcla, seleccione Embed In > Navigation Controller en el menú Editor. Algunas cosas cambian:

  • el controlador de navegación se convierte en el controlador de vista inicial del storyboard
  • se agrega una nueva escena llamada Navigation Controller Scene
  • se agrega una barra de navegación al controlador de vista de navegación y autores
  • el controlador de navegación y el controlador de vista de los autores están conectados por un segue
Adding a Navigation ControllerAdding a Navigation ControllerAdding a Navigation Controller

Los Segues son comunes en storyboard y aprenderemos más sobre ellos más adelante en esta serie. Hay varios tipos de segues y el segue que conecta el controlador de navegación y el controlador de vista de authors es una relationship segue.

Cada controlador de navegación tiene un controlador de vista raíz, el controlador de vista en la parte inferior de navigation stack. No se puede extraer de la pila de navegación, porque un controlador de navegación siempre necesita un controlador de vista para mostrar al usuario. La transición de la relación entre el controlador de navegación y el controlador de vista del autor simboliza que este último es el controlador de vista raíz del controlador de navegación.

La barra de navegación en la parte superior del controlador de navegación y el controlador de vista de autores es algo que obtienes de forma gratuita cuando trabajas con controladores de navegación. Es una instancia de UINavigationBar y ayuda a navegar en la navigation stack.

Aunque el controlador de navegación es el controlador de vista inicial storyboard, el controlador de vista de los autores es el primer controlador de vista que veremos al iniciar la aplicación. Como mencioné anteriormente, el controlador de navegación no es más que un contenedor que ayuda a navegar entre una jerarquía de controladores de vista. Su vista está poblada por las vistas de los controladores de vista en su navigation stack.

Para agregar un título a la barra de navegación, agregue la siguiente línea al método viewDidLoad() de la clase AuthorsViewController.

1
// Set Title

2
title = "Authors"

Cada controlador de vista tiene una propiedad title que se usa en varios lugares. La barra de navegación es uno de ellos. Ejecute la aplicación para ver el resultado de este pequeño cambio.

Empujando y estallaando

Añadamos ahora la posibilidad de ver una lista de libros cuando el usuario toca el nombre de un autor. Esto significa que tenemos que capturar la selección (el nombre del autor) instanciar un nuevo controlador de vista basado en esa selección, y empujar el nuevo controlador de vista en navigation stack. ¿Suena complicado? No lo es. Deja que te enseñe.

Otro controlador de vista de tabla

¿Por qué no mostrar la lista de libros en otra vista de tabla? Cree una nueva subclase de UITableViewController y asígnele el nombre BooksViewController.

Create the BooksViewController ClassCreate the BooksViewController ClassCreate the BooksViewController Class

Cargar la lista de libros es fácil, como vimos anteriormente, pero ¿cómo sabe el controlador de ver libros qué autor ha tocado el usuario? Hay varias maneras de decirle al nuevo controlador de vista acerca de la selección del usuario, pero el enfoque que recomienda Apple se conoce como pasar por referencia. ¿Como funciona esto?

El controlador de vista de libros declara una propiedad author que podemos configurar para configurar el controlador de vista de libros. El controlador de vista de libros usa la propiedad author para mostrar los libros del autor seleccionado. Abra BooksViewController.swift y agregue una propiedad variable de tipo [String: AnyObject]! y nombrelo author.

1
import UIKit
2
3
class BooksViewController: UIViewController {
4
5
    var author: [String: AnyObject]!
6
    
7
    ...
8
    
9
}

¿Por qué no declaramos author como [String: AnyObject]?  o [String: AnyObject]? Debido a que una variable necesita tener un valor inicial, no podemos declarar al author como [String: AnyObject]. Podríamos usar [String: AnyObject]?, pero eso significaría que tendríamos que desenvolver el opcional cada vez que queremos acceder a su valor.

En Swift, normalmente usará opciones opcionales no envueltas forzadas si sabe que la propiedad tiene un valor y, más importante aún, si necesita tener un valor para que su aplicación funcione como se espera. Si la propiedad author no tiene un valor, entonces el controlador de vista de libros nos sirve de poco, ya que no podría mostrar ningún dato.

Para facilitar el acceso a los libros del autor, también declaramos una propiedad calculada. Como su nombre lo indica, una propiedad calculada no almacena un valor. Define un getter y / o setter para obtener y establecer el valor de otra propiedad. Eche un vistazo a la propiedad computada books a continuación.

1
var books: [AnyObject] {
2
    get {
3
        if let books = author["Books"] as? [AnyObject] {
4
            return books
5
        } else {
6
            return [AnyObject]()
7
        }
8
    }
9
}

El valor de los books depende del valor del author. Comprobamos si el autor tiene un valor para las claves "Books" y disminuimos el valor de una matriz de objetos AnyObject. Si el autor no tiene un valor para "Books", creamos una matriz vacía de tipo [AnyObject]. Debido a que la propiedad books calculados solo define un getter, podemos simplificar la implementación de esta manera:

1
var books: [AnyObject] {
2
    if let books = author["Books"] as? [AnyObject] {
3
        return books
4
    } else {
5
        return [AnyObject]()
6
    }
7
}

El resto de la clase BooksViewController es fácil. Eche un vistazo a las implementaciones de los tres métodos de protocolo UITableViewDataSource que se muestran a continuación.

1
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
2
    return 1
3
}
4
5
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
6
    return books.count
7
}
8
9
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
10
    // Dequeue Resuable Cell

11
    let cell = tableView.dequeueReusableCellWithIdentifier(CellIdentifier, forIndexPath: indexPath)
12
    
13
    if let book = books[indexPath.row] as? [String: String], let title = book["Title"] {
14
        // Configure Cell

15
        cell.textLabel?.text = title
16
    }
17
    
18
    return cell;
19
}

Esto también significa que tenemos que declarar una propiedad constante para el identificador de reutilización de celda y registrar una clase para la reutilización de celda en viewDidLoad(). Esto no es nada nuevo.

1
import UIKit
2
3
class BooksViewController: UITableViewController {
4
5
    let CellIdentifier = "Cell Identifier"
6
    
7
    ...
8
    
9
}
1
override func viewDidLoad() {
2
    super.viewDidLoad()
3
    
4
    tableView.registerClass(UITableViewCell.classForCoder(), forCellReuseIdentifier: CellIdentifier)
5
}

Empujando un controlador de vista

Cuando el usuario toca el nombre de un autor en el controlador de vista de autores, la aplicación debe mostrar la lista de libros escritos por ese autor. Esto significa que necesitamos instanciar una instancia de la clase BooksViewController , decirle a la instancia qué autor fue seleccionado por el usuario, y empujar el nuevo controlador de vista a la navigation stack.

Storyboards nos ayudará con esto. Abra Main.storyboard, arrastre otra instancia de UITableViewController desde la Object Library, y establezca su clase en BooksViewController en Identity Inspector.

Add Books View Controller to StoryboardAdd Books View Controller to StoryboardAdd Books View Controller to Storyboard

Seleccione la vista de tabla en el nuevo controlador de vista y establezca el número de Prototype Cells en 0 en el Attributes Inspector. Para insertar el controlador de vista de libros en la pila de navegación del controlador de navegación, debemos crear otro segue. Esta vez, sin embargo, creamos un segue manual, un show segue para ser precisos.

Seleccione el controlador de vista de autores en el guión gráfico, mantenga presionada la tecla Control y arrastre desde el controlador de vista de autores al controlador de vista de libros. Seleccione Manual Segue > Show en el menú que aparece para crear una transición del controlador de vista de autores al controlador de vista de libros.

Create a Manual Show SegueCreate a Manual Show SegueCreate a Manual Show Segue

Hay una cosa más que debemos hacer antes de volver a la implementación del controlador de vista de libros. Seleccione el segue que creamos, abra el Attributes Inspector a la derecha y establezca el Identifier de segue en BooksViewController. Al darle un nombre al segue, podemos referirnos a él más adelante en el código.

Setting the Segue IdentifierSetting the Segue IdentifierSetting the Segue Identifier

Para poner el segue para usar, necesitamos implementar tableView(_:didSelectRowAtIndexPath:) en el controlador de vista de autores. Este método se define en el protocolo UITableViewDelegate como vimos en el artículo anterior sobre vistas de tabla. En este método, invocamos performSegueWithIdentifier(_:sender:) para realizar el segue que creamos en el storyboard. El método performSegueWithIdentifier(_:sender:) toma dos argumentos, el identificador del segue y el emisor del mensaje. Ahora debería estar claro por qué le dimos al segue un identificador en el storyboard. También tenga en cuenta que reiniciamos la selección después de realizar el segue.

1
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
2
    // Perform Segue

3
    performSegueWithIdentifier(SegueBooksViewController, sender: self)
4
    
5
    tableView.deselectRowAtIndexPath(indexPath, animated: true)
6
}

La constante SegueBooksViewController es otra propiedad constante de la clase AuthorsViewController.

1
import UIKit
2
3
class AuthorsViewController: UITableViewController {
4
5
    let CellIdentifier = "Cell Identifier"
6
    let SegueBooksViewController = "BooksViewController"
7
    
8
    ...
9
10
}

Antes de realizar una segue, el controlador de vista tiene la oportunidad de prepararse para el segue en prepareForSegue(_:sender:). En este método, el controlador de vista puede configurar el controlador de vista de destino, el controlador de vista de libros. Implementemos prepareForSegue(_:sender:) para ver cómo funciona esto.

1
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
2
    if segue.identifier == SegueBooksViewController {
3
        if let indexPath = tableView.indexPathForSelectedRow, let author = authors[indexPath.row] as? [String: AnyObject]  {
4
            let destinationViewController = segue.destinationViewController as! BooksViewController
5
            destinationViewController.author = author
6
        }
7
    }
8
}

Este método se invoca cada vez que se realiza una segue. Primero verificamos si el identificador del segue es igual a SegueBooksViewController. A continuación, solicitamos a la vista de tabla la ruta de índice de la selección actual mediante el enlace opcional. Si se selecciona una fila, preguntamos a los autores por el authors que corresponde con esta selección.

En la instrucción if, obtenemos una referencia al controlador de vista de libros (el controlador de vista de destino del segue) y establecemos su propiedad author para el autor seleccionado actualmente en la vista de tabla.

¿Se estará preguntando cuándo o dónde inicializamos el controlador de vista de libros? No instanciamos explícitamente una instancia del controlador de vista de libros. El storyboard sabe qué clase necesita para crear instancias e inicializar una instancia de BooksViewController para nosotros.

Antes de ejecutar su aplicación, abra BooksViewController.swift y configure el título del controlador de vista con el nombre del autor para actualizar el título de la barra de navegación.

1
override func viewDidLoad() {
2
    super.viewDidLoad()
3
    
4
    if let name = author["Author"] as? String {
5
        title = name
6
    }
7
    
8
    tableView.registerClass(UITableViewCell.classForCoder(), forCellReuseIdentifier: CellIdentifier)
9
}

}Ejecuta la aplicación. Toque el nombre de un autor en la vista de tabla y observe cómo se inserta una nueva instancia de BooksViewController en navigation stack y se muestra al usuario. ¿Has notado que también recibimos un botón de retroceso gratis cuando usamos un controlador de navegación? El título del controlador de vista anterior se utiliza como el título del botón Atrás.

Agregar una portada de libro

Cuando el usuario toca un libro en el controlador de vista de libros, la aplicación debe mostrar la portada del libro. No usaremos un controlador de vista de tabla para esto. En su lugar, usamos una subclase simple UIViewController y mostramos la portada del libro en una instancia de la clase UIImageView. UIImageView es una subclase de UIView especializada en mostrar imágenes.

Cree una nueva subclase de UIViewController, no UITableViewController, y asígnele el nombre BookCoverViewController.

Creating the BookCoverViewController ClassCreating the BookCoverViewController ClassCreating the BookCoverViewController Class

Necesitamos declarar dos propiedades almacenadas en el nuevo controlador de vista. La primera propiedad almacenada es una referencia a la vista de la imagen que vamos a utilizar para mostrar la portada del libro. La palabra clave @IBOutlet indica que haremos la conexión en el storyboard. La segunda propiedad almacenada, Book, es de tipo [String: String]! Esta propiedad representa el libro que se muestra en el controlador de vista de portada del libro.

1
import UIKit
2
3
class BookCoverViewController: UIViewController {
4
5
    @IBOutlet var bookCoverView: UIImageView!
6
    
7
    var book: [String: String]!
8
    
9
    ...
10
11
}

Abra Main.storyboard para crear la interfaz de usuario del controlador de vista de libro. Arrastre una instancia de UIViewController desde la Object Library al área de trabajo y configure su clase en BookCoverViewController en el Identity Inspector.

Adding a View Controller to the WorkspaceAdding a View Controller to the WorkspaceAdding a View Controller to the Workspace

Arrastre una instancia de UIImageView desde la Object Library a la vista del controlador de vista y haga que cubra toda la vista del controlador de vista. En Connections Inspector, conéctelo con la outlet  bookCoverView del controlador de vista.

Adding an Image ViewAdding an Image ViewAdding an Image View

Para asegurarnos de que la vista de la imagen se muestra correctamente en todos los dispositivos, debemos aplicar las restricciones de diseño necesarias, como se muestra a continuación.

Adding Layout Constraints to the Image ViewAdding Layout Constraints to the Image ViewAdding Layout Constraints to the Image View

Antes de implementar el controlador de vista, cree un push segue entre el controlador de vista de libros y el controlador de vista de portada del libro. Seleccione el segue y establezca su identificador en BookCoverViewController en el Attributes Inspector.

Creating a Segue to the Book Cover View ControllerCreating a Segue to the Book Cover View ControllerCreating a Segue to the Book Cover View Controller

En la clase BooksViewController, declare una propiedad constante para el identificador de segue.

1
import UIKit
2
3
class BooksViewController: UITableViewController {
4
5
    let CellIdentifier = "Cell Identifier"
6
    let SegueBookCoverViewController = "BookCoverViewController"
7
    
8
    ...
9
10
}

Usamos esta propiedad en tableView(_:didSelectRowAtIndexPath:) para realizar el segue que creamos en el guión gráfico. No olvide anular la selección de la fila después de realizar el cambio.

1
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
2
    // Perform Segue

3
    performSegueWithIdentifier(SegueBookCoverViewController, sender: self)
4
    
5
    tableView.deselectRowAtIndexPath(indexPath, animated: true)
6
}

La implementación de prepareForSegue(_:sender:) es muy similar a la de la clase BooksViewController. Verificamos si el identificador de segue es igual a SegueBookCoverViewController y solicitamos a la vista de tabla la ruta de índice de la fila seleccionada actualmente. Solicitamos books para el libro que correspondan con la selección del usuario y establecemos la propiedad book del controlador de vista de destino, una instancia de BookCoverViewController.

1
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
2
    if segue.identifier == SegueBookCoverViewController {
3
        if let indexPath = tableView.indexPathForSelectedRow, let book = books[indexPath.row] as? [String: String]  {
4
            let destinationViewController = segue.destinationViewController as! BookCoverViewController
5
            destinationViewController.book = book
6
        }
7
    }
8
}

Configuramos la vista de la imagen de la clase BookCoverViewController en su método viewDidLoad(). Pedimos a book el valor de la clave "Cover" y se crea una instancia de un objeto UIImage invocando el inicializador init(named:), pasando el nombre del archivo. Asignamos el objeto UIImage a la propiedad image de bookCoverView.

1
override func viewDidLoad() {
2
    super.viewDidLoad()
3
    
4
    if let fileName = book["Cover"] {
5
        bookCoverView.image = UIImage(named: fileName)
6
        bookCoverView.contentMode = .ScaleAspectFit
7
    }
8
}

En viewDidLoad(), también configuramos el modo de contenido de la vista de imagen en ScaleAspectFit. La propiedad contentMode es del tipo UIViewContentMode, una enumeración. El valor que asignamos, ScaleAspectFit, le dice a la vista de la imagen que estire la imagen tanto como sea posible respetando su relación de aspecto.

Ejecuta la aplicación y pruébala. Ahora debería poder navegar por los libros almacenados en Books.plist.

¿Dónde estalla?

Anteriormente en este artículo, expliqué que los controladores de vista pueden ser empujados y levantados desde una navigation stack. Hasta ahora, solo hemos enviado los controladores de vista a una navigation stack. Hacer estallar un controlador de vista desde una navigation stack se lleva a cabo cuando el usuario toca el botón Atrás de la barra de navegación. Esta es otra funcionalidad que obtenemos de forma gratuita.

En algún momento, sin embargo, se encontrará con una situación en la que manualmente debe mostrar un controlador de vista desde una navigation stack. Puede hacerlo llamando a popViewControllerAnimated(_:) en el controlador de vista de navegación. Esto elimina el controlador de vista superior de la navigation stack.

De forma alternativa, puede mostrar todos los controladores de vista de la pila de navegación, con la excepción del controlador de vista raíz, al llamar a popToRootViewControllerAnimated(_:) en el controlador de navegación.

¿Cómo se accede al controlador de navegación de un controlador de vista? La clase UIViewController declara una propiedad calculada, navigationController, de tipo UINavigationController?. Si el controlador de vista está en una pila de navegación, esta propiedad hace referencia al controlador de navegación al que pertenece la navigation stack.

Conclusion

Espero que estén de acuerdo en que los controladores de navegación no son tan complicados. Este artículo podría haber sido mucho más corto, pero espero que hayas aprendido algunas cosas más en el camino. En el siguiente artículo, echamos un vistazo a los controladores de navegacion de pestañas. Aunque los controladores de barra de pestañas también administran una colección de controladores de vista, son bastante diferentes de los controladores de navegación.

Si tiene preguntas o comentarios, puede dejarlos en los comentarios a continuación o comunicarse conmigo en Twitter.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.