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

Swift desde Cero: Herencia y Protocolos

Scroll to top
Read Time: 12 min
This post is part of a series called Swift From Scratch.
Swift From Scratch: An Introduction to Classes and Structures
Swift From Scratch: Delegation and Properties

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

Si has leído los artículos anteriores de esta serie, deberías tener un buen entendimiento de los fundamentos del lenguaje de programación Swift por ahora. Hablamos sobre variables, constantes, y funciones, y en el artículo anterior cubrimos los básicos de programación orientada a objetos en Swift.

Mientras que los playgrounds son una gran herramienta para jugar con Swift y aprender el lenguaje, es tiempo de continuar y crear nuestro primer proyecto Swift en Xcode. En este artículo, vamos a crear los cimientos de una aplicación simple de tareas por hacer usando Xcode y Swift. A lo largo del camino, aprenderemos más sobre programación orientada a objetos y también echaremos un vistazo más cercano a la integración entre Swift y Objective-C.

Prerrequisitos

Si quisieras seguir a la par conmigo, entonces asegúrate de que tienes Xcode 6.3 o superior instalado en tu máquina. Al tiempo de la escritura, Xcode 6.3 está en beta y disponible desde el iOS Dev Center de Apple para desarrolladores iOS registrados.

La razón de requerir Xcode 6.3 o superior es poder sacar ventaja de Swift 1.2, el cuál introdujo Apple hace unos cuantos días. Swift 1.2 introduce un número de adiciones grandiosas de las que sacaremos ventaja en el resto de la serie.

1. Configuración de Proyecto

Paso 1: Elige una Plantilla

Lanza Xcode 6.3 o superior y selecciona Nuevo > Proyecto... desde el menú Archivo. Desde la lista de plantillas de Aplicación iOS, elige la plantilla Single View Application y da clic en Siguiente.

Paso 2: Configura el Proyecto

Nombra el proyecto ToDo y establece Lenguaje a Swift. Asegúrate de que Dispositivos está establecido a iPhone y la etiqueta etiquetada como Use Core Data está desmarcada. Da clic en Next para continuar.

Dile a Xcode en dónde quisieras almacenar tu proyecto y da clic en Crear en la parte inferior derecha para crear tu primer proyecto Swift.

2. Anatomía del Proyecto

Antes de que continuemos nuestro viaje a Swift, tomemos un momento para ver lo que Xcode ha creado por nosotros. Si eres nuevo en Xcode y desarrollo iOS, entonces la mayoría de esto será nuevo para ti. Trabajando con un proyecto Swift, sin embargo, te dará una mejor idea de cómo lucen y se comportan las estructuras y clases en Swift.

La plantilla de proyecto no difiere mucho de un proyecto creado con Objective-C como el lenguaje de programación. Las diferencias más importantes están relacionadas a las clases AppDelegate y ViewController.

Si has trabajado con Objective-C en el pasado, entonces notarás que la plantilla de proyecto contiene menos archivos. No hay archivos header (.h) o implementation (.m) en nuestro proyecto. En Swift, las clases no tienen archivo header separado en el cuál la interfaz es declarada. En su lugar, una clase es declarada e implementada en un solo archivo .swift.

Nuestro proyecto actualmente contiene dos archivos Swift, uno para la clase AppDelegate, AppDelegate.swift, y otro para la clase ViewController, ViewController.swift. El proyecto también incluye un storyboard, Main.storyboard, y un archivo XIB para la pantalla de inicio, LaunchScreen.xib. Trabajaremos con el storyboard un poco después en este artículo. Este actualmente solo contiene la escena para la clase ViewController.

Hay un número de otros archivos y carpetas incluidas en el proyecto, pero vamos a ignorarlas por ahora. No juegan un papel importante en el alcance de este artículo.

3. Herencia

La primera cosa que tocaremos en este artículo es herencia, un paradigma común en la programación orientada a objetos. En Swift, solo las clases pueden heredar de otra clase. En otras palabras, las estructuras y enumeraciones no soportan herencia. Esta es una de las diferencias clave entre clases y estructuras.

Abre ViewController.swift para ver la herencia en acción. La interfaz e implementación de la clase ViewController es bastante simple, lo que hará más sencillo para nosotros concentrarnos en lo esencial.

UIKit

Al inicio de ViewController.swift, deberías ver una declaración import para el framework UIKit. Recuerda que el framework UIKit proporciona la infraestructura para crear una aplicación iOS funcional. La declaración import al inicio hace esta infraestructura disponible para nosotros en ViewController.swift.

1
import UIKit

Superclase

Debajo de la declaración import, definimos una nueva clase llamada ViewController. La coma después del nombre de la clase no se traduce a is of type como vimos anteriormente en esta serie. En su lugar, la clase después de la coma es la superclase de la clase ViewController. En otras palabras, el siguiente pedazo de código podría ser leído mientras definimos una clase llamada ViewController que hereda de UIViewController.

1
class ViewController: UIViewController {
2
3
}

Esto también explica la presencia de la declaración import al inicio de ViewController.swift ya que la clase UIViewController está definida en el framework UIKit.

Anulaciones

La clase ViewController actualmente incluye dos métodos, pero nota que cada método está prefijado con la palabra clave override. Esto indica que los métodos están definidos en la superclase de la clase---o más alto en el árbol de herencia---y están anulados por la clase ViewController.

1
class ViewController: UIViewController {
2
3
    override func viewDidLoad() {
4
        super.viewDidLoad()
5
    }
6
7
    override func didReceiveMemoryWarning() {
8
        super.didReceiveMemoryWarning()
9
    }
10
}

El constructor override no existe en Objective-C. En Objective-C, implementas un método anulado en una subclase sin indicar explícitamente que anula un método más arriba en el árbol de herencia. El tiempo de ejecución Objective-C se encarga del resto.

Lo mismo es verdad en Swift, pero las palabras clave override agregan seguridad a la anulación de método. Debido a que prefijamos el método viewDidLoad con la palabra clave override, Swift espera este método en la superclase de la clase o más arriba en el árbol de herencia. Puesto de manera simple, si anulas un método que no existe en el árbol de herencia, Swift arrojará un error. Puedes probar esto escribiendo mal el método viewDidLoad como se muestra abajo.

4. Interfaz de Usuario

Declarando Outlets

Agreguemos una vista de tabla al controlador de vista para mostrar una lista de elementos por hacer. Antes de que hagamos eso, necesitamos crear un outlet para la vista de tabla. Un outlet no es nada más que una propiedad que es visible para y puede ser establecida en Constructor de Interfaz. Para declarar un outlet en la clase ViewController, prefijamos la propiedad, una variable, con el atributo @IBOutlet.

1
class ViewController: UIViewController {
2
    @IBOutlet var tableView: UITableView!
3
    
4
    override func viewDidLoad() {
5
        super.viewDidLoad()
6
    }
7
8
    override func didReceiveMemoryWarning() {
9
        super.didReceiveMemoryWarning()
10
    }
11
}

Nota que el outlet es un opcional implícitamente desenvuelto. ¿Un qué? Déjame comenzar diciendo que un outlet siempre necesita ser un tipo opcional. La razón es simple. Cada propiedad de la clase ViewController necesita tener un valor después de inicialización. Un outlet, sin embargo, solo está conectado a la interfaz de usuario en tiempo de ejecución después de que la instancia ViewController ha sido inicializada de ahí el tipo opcional.

Espera un minuto. El outlet tableView está declarado como un opcional implícitamente desenvuelto, no un opcional. No hay problema. Podemos declarar el outlet tableView como un opcional reemplazando el signo de exclamación en el código de arriba con un signo de interrogación. Eso se compilaría bien. Sin embargo, esto también significaría que necesitaríamos desenvolver explícitamente la propiedad cada vez que quisiéramos acceder al valor almacenado en el opcional. Esto puede volverse rápidamente incómodo y verboso.

En su lugar, declaramos el outlet tableView como un opcional implícitamente desenvuelto, lo que significa que no necesitamos desenvolver explícitamente el opcional si necesitamos acceder a su valor. En corto, un opcional implícitamente desenvuelto es un opcional, pero podemos acceder al valor almacenado en el opcional como una variable regular. Lo importante a tener en mente es que tu aplicación fallará si intentas acceder a su valor si no se ha establecido un valor. Esa es la trampa. Si el outlet está conectado apropiadamente, sin embargo, podemos estar seguros de que está establecido cuando accedemos por primera vez a este.

Conectando Outlets

Con el outlet declarado, es tiempo de conectarlo en Interface Builder. Abre Main.storyboard, y selecciona el controlador de vista. Elige Embed In > Navigation Controller desde el menú Editor. Esto establecerá el controlador de vista como el controlador de vista raíz de un controlador de navegación. No te preocupes por esto por ahora.

Arrastra una instancia UITableView desde la Librería de Objetos a la vista del controlador de vista, y agrega las restricciones de diseño necesarias. Con la vista de tabla seleccionada, abre el Inspector de Conexiones y establece los outlets dataSource y delegate de la vista de tabla al controlador de vista.

Con el Inspector de Conexiones aún abierto, selecciona el controlador de vista y conecta el outlet tableView a la vista de tabla que recién agregamos. Esto conectará el outlet tableView de la clase ViewController a la vista de tabla.

5. Protocolos

Antes de que podamos construir y ejecutar la aplicación, necesitamos implementar los protocolos UITableViewDataSource y UITableViewDelegate en la clase ViewController. Esto involucra varias cosas.

Paso 1: Conformando a Protocolos

Necesitamos decirle al compilador que la clase ViewController conforma a los protocolos UITableViewDataSource y UITableViewDelegate. La sintáxis luce similar a aquella en Objective-C.

1
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
2
    ...
3
}

Los protocolos a los que conforma la clase están listados después de la superclase, UIViewController en el ejemplo de arriba. Si la clase no tiene una superclase, lo cuál no es poco común en Swift, entonces los protocolos son listados inmediatamente después del nombre y coma de la clase.

Paso 2: Implementando el Protocolo UITableViewDataSource

Debido a que el protocolo UITableViewDelegate no define métodos requeridos, solo vamos a implementar el protocolo UITableViewDataSource por ahora. Antes de que lo hagamos, creemos una propiedad variable para almacenar los elementos por hacer que vamos a listar en la vista de tabla.

1
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
2
    @IBOutlet var tableView: UITableView!
3
    
4
    var items: [String] = []
5
    
6
    ...
7
}

Declaramos una propiedad variable items de tipo [String] y establecemos un arreglo vacío, [], como el valor inicial. Esto debería lucir familiar por ahora. Después, implementemos los dos métodos requeridos del protocolo UITableViewDataSource.

El primer método requerido, numberOfRowsInSection(_:), es sencillo. Simplemente devolvemos el número de elementos almacenados en la propiedad items.

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

El segundo método requerido, cellForRowAtIndexPath(_:), necesita un poco más de explicación. Usando sintaxis de suscripción, pedimos el elemento correcto del arreglo de elementos por hacer.

1
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
2
    // Fetch Item

3
    let item = self.items[indexPath.row]
4
    
5
    // Dequeue Table View Cell

6
    let tableViewCell = tableView.dequeueReusableCellWithIdentifier("TableViewCell", forIndexPath: indexPath) as! UITableViewCell
7
    
8
    // Configure Table View Cell

9
    tableViewCell.textLabel?.text = item
10
    
11
    return tableViewCell
12
}

Después pedimos a la vista de tabla una celda con identificador "TableViewCell", pasando la ruta raíz para la fila actual. Nota que almacenamos la celda en una constante llamada tableViewCell. No hay necesidad de declarar tableViewCell como variable.

Otro detalle importante es que se degradró el valor devuelto de dequeueReusableCellWithIdentifier(_:forIndexPath:) a UITableViewCell puesto que devuelve un objeto de tipo AnyObject, que equivale a id en Objective-C. Para degradar AnyObjectUITableViewCell, usamos la palabra clave as.

Podrías usar la variable as? para degradar a un tipo opcional, pero ya que podemos estar seguros de que dequeueReusableCellWithIdentifier(_:forIndexPath:) siempre devuelve una instancia apropiadamente inicializada, podemos usar la palabra clave as!, desenvolviendo implícitamente el resultado de la llamada del método.

En la siguiente línea de código, configuramos la celda de vista de tabla, estableciendo el texto de la etiqueta de texto con el valor de item. Nota que en Swift la propiedad textLabel de UITableViewCell es declarada como un tipo opcional por lo tanto el signo de interrogación. Esta línea de código podría leerse como propiedad text de la etiqueta texto al item si textLabel no es igual a nil. En otras palabras, la propiedad text de la etiqueta solo es establecida si textLabel no es nil. Este es un constructor bastante seguro convenientemente en Swift conocido como encadenamiento opcional.

Paso 3: Re-uso de Celda

Hay dos cosas que necesitamos sortear antes de construir la aplicación. Primero, necesitamos decirla a la vista de tabla que necesita usar la clase UITableViewCell para crear nuevas celdas de vista de tabla. Hacemos esto invocando registerClass(_:forCellReuseIdentifier:), pasando la clase UITableViewCell y el identificador de re-uso que usamos antes, "TableViewCell". Actualiza el método viewDidLoad como se muestra abajo.

1
override func viewDidLoad() {
2
    super.viewDidLoad()
3
    
4
    // Register Class for Cell Reuse

5
    self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "TableViewCell")
6
}

Paso 4: Agregando Elementos

Actualmente no tenemos ningún elemento para mostrar en la vista de tabla. Esto es resuelto de manera sencilla poblando la propiedad items con unos cuantos elementos por hacer. Hay varias maneras de lograr esto. He elegido poblar la propiedad items en el método viewDidLoad como se muestra abajo.

1
override func viewDidLoad() {
2
    super.viewDidLoad()
3
    
4
    // Populate Items

5
    self.items = ["Buy Milk", "Finish Tutorial", "Play Minecraft"]
6
    
7
    // Register Class for Cell Reuse

8
    self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "TableViewCell")
9
}

6. Construye y Ejecuta

Es tiempo de llevar de probar nuestra aplicación. Selecciona Run desde el menú Product de Xcode o presiona Command-R. Si has seguido a la par y estás usando Swift 1.2, deberías terminar con el siguiente resultado.

Nota que he agregado un título, To Do, al inicio de la vista en la barra de navegación. Puedes hacer lo mismo estableciendo la propiedad title de la instancia ViewController en el método viewDidLoad.

1
override func viewDidLoad() {
2
    super.viewDidLoad()
3
    
4
    // Set Title

5
    self.title = "To Do"
6
    
7
    // Populate Items

8
    self.items = ["Buy Milk", "Finish Tutorial", "Play Minecraft"]
9
    
10
    // Register Class for Cell Reuse

11
    self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "TableViewCell")
12
}

Aprende Más en Nuestro Curso de Programación Swift

Si estás interesado en llevar tu educación Swift al siguiente nivel, puedes echar un vistazo a nuestro curso completo sobre desarrollo Swift.

Conclusión

Incluso aunque hemos creado una aplicación simple, has aprendido algunas cosas nuevas. Hemos explorado herencia y anular métodos. También cubrimos protocolos y cómo adoptar el protocolo UITableViewDataSource en la clase ViewController. La cosa más importante que has aprendido, sin embargo, es cómo interactuar con APIs Objective-C.

Es importante entender que las APIs del SDK iOS son escritas en Objective-C. Swift fue diseñado para ser compatible con estas APIs. Basado en fracasos anteriores, Apple entendió que Swift necesitaba poder engancharse al SDK iOS sin tener que re-escribir cada API en Swift.

Combinar Objective-C y Swift es posible, pero hay algunas advertencias que exploraremos a más detalles mientras avancemos. Debido al implacable enfoque de Swift en seguridad, necesitamos que sortear algunos obstáculos de vez en cuando. Sin embargo, ninguno de estos obstáculos son demasiado difíciles de sortear como averiguaremos en el siguiente artículo en el cuál continuaremos trabajando sobre nuestra aplicación de tareas por hacer.

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.