Delegates en Swift: como declarar y usar un protocolo para manejar eventos externos

Publicado el enero 29, 2016 · Publicado en Sin categoría

En este artículo aprenderemos a partir de un ejemplo básico, como utilizar un protocolo en Swift para manejar eventos enviados desde una clase externa. Aprenderemos como declarar un protocolo y, como definir el delegado del protocolo dentro de la clase que va a manejar sus eventos. En este ejemplo en particular, implementaremos una función externa que se encarga de descargar información de manera asíncrona y una vez completada la descarga, llama al protocolo para comunicarle como el resultado de esta.

Para empezar hemos de crear una Single View Application en lenguaje Swift.

 Cuadro 1

En este ejemplo vamos a realizar una petición no segura HTTP, por lo que, si estamos utilizando iOS9 o versiones posteriores, necesitaremos autorizar estas peticiones modificando el fichero info.plist. Para ello hacemos click derecho en el fichero, seleccionamos Open As, seleccionamos Source code y añadimos las siguientes lineas para permitir el uso del protocolo HTTP para nuestra app:

<key>NSAppTransportSecurity</key>
<dict>
            <key>NSAllowsArbitraryLoads</key>
            <true/>
</dict>

Declaración del protocolo

Continuemos ahora creando un nuevo fichero Swift. Aquí es donde vamos a definir los métodos que contendrá nuestro protocolo.

 Cuadro2

Un protocolo se declara según el siguiente formato:

         @objc protocol nombre_del_protocolo {
                       func funcion_del_protocolo(data: AnyObject)
                       optional func funcion_opcional_del_protocolo()
}

Podemos definir las funciones que van a ser manejadas por el delegado y los parámetros de estas. También podemos utilizar la palabra reservada optional, indicando que la función en cuestión no tiene porque ser implementada obligatoriamente.

 El protocolo que vamos a definir en nuestro ejemplo se ocupara de manejar los eventos resultado después de realizar una descarga, por ello tendrá la siguiente forma:

          @objc protocol DataResultDelegate {
                       func success(data: NSData)
                       optional func error()
         }

Definición de la función de descarga

Para continuar vamos a definir la función que se encargará de realizar la descarga y llamar al protocolo una vez completada.

Creamos un nuevo fichero Swift de la misma forma que hicimos anteriormente. En el es donde definiremos e implementaremos la función encargada de realizar la petición HTTP asíncrona y descargar la información. Como parámetros le pasaremos el enlace de donde realizar la petición y el protocolo que manejara los eventos resultado de la petición.

func downloadFromUrl(stringURL: String, handler: DataResultDelegate) {
   //Inicializamos parámetros de la petición
   let url = NSURL(string: stringURL)!
   let session = NSURLSession.sharedSession()
   let request = NSMutableURLRequest(URL: url)
   request.timeoutInterval = 8
   //Definimos comportamiento para el resultado de la petición
   let asyncDownloadTask = session.dataTaskWithRequest(request) { (data, response, error) -> Void in
       guard let data = data else {
           if let errorCallback = handler.error {
               errorCallback()
           }
           return
       }
       handler.success(data)
   }
   //Realizamos la petición
   asyncDownloadTask.resume()
}

Implementación del delegado

Por último hemos de definir e implementar la clase delegada que va a manejar los eventos del protocolo.

Para ello seleccionamos el fichero ViewController.swift y definimos la clase ViewController como implementación del protocolo DataResultDelegate:

class ViewController: UIViewController, DataResultDelegate {

Al no tener implementados aún las funciones declaradas en el protocolo nos saltará un error:

Type ‘ViewController’ does not conform to protocol ‘DataResultDelegate’”. Para ajustar la clase al protocolo hemos de definir la implementación para las funciones declaradas.

   func success(data: NSData) {
       let strData = NSString(data: data, encoding: NSUTF8StringEncoding)
       print(strData)
   }
   func error() {
       print(“error”)
   }

Para terminar, si queremos probar el funcionamiento del ejemplo solo tenemos que llamar a la función downloadFromUrl y comprobar como realmente nuestro delegado recibe los eventos resultado de la descarga:

   override func viewDidLoad() {
       super.viewDidLoad()
       let httpFuncions = HTTPFunctions()
       httpFuncions.downloadFromUrl(“link”, handler: self)
   }

 

ADRIÁN MARTÍNEZ