Antes de continuar con la serie de tutoriales sobre como crear un juego como Gorilla Rush, me pareció útil escribir un par de post acerca de algunas características de Swift, las cuales vamos a utilizar en los tutoriales.
En esta ocasión voy a hablar acerca de protocolos. Los protocolos probablemente sea algo nuevo para ti, pues si tienes experiencia en lenguajes como C# o Java seguramente has utilizado o leído sobre interfaces… bueno, eso es lo que un protocolo es en Swift.
No vamos a entrar en muchos detalles en este post sobre qué es una interfaz o protocolo, o cuándo usarlos o cuándo no, sobre esto hay bastante documentación en la web. Vamos en enfocarnos más en cuál es su sintaxis en Swift y algún que otro ejemplo.
En Swift, un protocolo es como un plano, que define métodos, propiedades y otros requerimientos que responden a una tarea en particular. Puede ser adoptado por una clase, estructura o enumeración con el objetivo de brindar una implementación a estos requerimientos. Cualquier tipo que implemente un determinado protocolo se dice que implementa (o se ajusta) a ese protocolo.
Sintaxis
Un protocolo se define de forma muy similar a una clase, estructura o enumeración:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// sintaxis de un protocolo | |
protocol UnProtocolo { | |
// aquí va la definición | |
} |
Para que un tipo pueda adoptar/implementar un protocolo, debe colocar el nombre del protocolo luego del nombre del tipo separados por el signo de dos puntos como parte de su definición, el tipo puede implementar más de un protocolo colocándolos separados por coma:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// estructura que implementa dos protocolos | |
struct UnaEstructura: UnProtocolo, OtroProtocolo { | |
// aquí va la definición | |
} |
Si una clase hereda de una super clase, coloca primero la superclase y luego los protocolos que implemente separados por coma:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// clase que hereda de una super clase e implementa dos protocolos | |
class UnaClase: SuperClase, UnProtocolo, OtroProtocolo { | |
// aquí va la definición | |
} |
Ejemplo
Antes de continuar veamos un ejemplo.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 1 | |
protocol Hablar { | |
func decirHola(nombre: String) | |
} | |
// 2 | |
class Persona: Hablar { | |
// 3 | |
func decirHola(nombre: String) { | |
// 4 | |
print("Hola (nombre).") | |
} | |
} | |
// 5 | |
var juliana = Persona() | |
var geykel = Persona() | |
// 6 | |
juliana.decirHola("Geykel") | |
geykel.decirHola("Juliana") |
- Primero definimos el protocolo Hablar el cual contiene un método, decirHola(nombre: String).
- Definimos la clase Persona que va a adoptar/implementar el protocolo Hablar.
- Brindamos una implementación al método decirHola(nombre: String) en la clase Persona.
- Este método sólo va a imprimir el texto “Hola” seguido del valor que se le pase a través de la variable nombre que es de tipo String.
- Creamos dos variables con los nombres juliana y geykel, ambas guardan una referencia a un objeto de tipo Persona.
- Finalmente invocamos el método decirHola en ambas variables y el resultado que veremos serán dos lineas, la primera: “Hola Geykel.”, y la segunda: “Hola Juliana.”.
Propiedades
En Swift un protocolo puede también requerir al tipo que lo implemente, definir propiedades, especificando el nombre y el tipo de la propiedad y si la misma servirá sólo para obtener un valor o si además permitirá establecer un valor.
El siguiente ejemplo muestra los dos casos:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ejemplo de protocolo con propiedades | |
protocol UnProtocolo { | |
var permiteEstablecerYDevolverUnValor: String { get set } | |
var permiteSoloDevolverUnValor: Int { get } | |
} |
La primera propiedad especifica que puede tanto establecer un valor como devolver un valor, y la segunda sólo devolver.
En la definición de propiedades en un protocolo no se especifica si son propiedades cuyo valor es calculado o si sólo es una propiedad para almacenar un valor; es responsabilidad del tipo que implemente el protocolo decidir esto.
En el siguiente ejemplo veremos un caso de propiedad calculada:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 1 | |
protocol NombreCompleto { | |
var nombreCompleto:String { get } | |
} | |
// 2 | |
class Persona: NombreCompleto { | |
// 3 | |
var nombre: String | |
var apellidos: String | |
// 4 | |
init(nombre: String, apellidos: String) { | |
self.nombre = nombre | |
self.apellidos = apellidos | |
} | |
// 5 | |
var nombreCompleto: String { | |
// 6 | |
return "(nombre) (apellidos)" | |
} | |
} | |
// 7 | |
var juan = Persona(nombre: "Juan", apellidos: "Pérez") | |
// 8 | |
print(juan.nombreCompleto) |
- Definimos el protocolo NombreCompleto el cual provee una definición de la propiedad nombreCompleto: String { get } la cual sólo puede ser utilizada para devolver un valor debido a que no contiene un set.
- Definimos la clase Persona que implementa el protocolo NombreCompleto.
- Definimos dos atributos de la clase Persona, nombre y apellidos de tipo String.
- Creamos un inicializador (conocido en otros lenguajes como constructor) el cual inicializa los atributos de la clase Persona.
- Ahora implementamos la propiedad nombreCompleto que adoptamos del protocolo NombreCompleto.
- Como desarrollador de la clase he decidido que el valor retornado por esta propiedad es calculado y es el resultado de concatenar el valor de los atributos nombre y apellidos.
- Creamos una variable llamada juan la cual guarda una referencia a un objeto de tipo Persona, este objeto fue creado utilizando el inicializador que definimos en el paso 4.
- Llamamos a la función print para visualizar el valor de la propiedad nombreCompleto el cual es “Juan Pérez”.
Esto es todo lo que quería cubrir en este post, es más que suficiente para cubrir las bases para la serie de tutoriales sobre Gorilla Rush.
Hay mucho más sobre protocolos en Swift, incluso algunas funcionalidades que no había visto antes en lenguajes como Java y C#. Si deseas conocer más puedes consultar la guía de Swift en el sitio para desarrolladores en Apple.
[…] Protocolos en Swift (básico) […]
[…] el protocolo Base que vamos a utilizar como tipo […]