Protocols en Swift

 

Un Protocol en Swift es como el plano de una casa que te define su planta. En Swift, un protocolo define métodos y funciones que otra entidad debe implementar. Define básicamente los requerimientos que una clase/struct/enum debe implementar para conformar con dicho protocolo.

Sintaxis y definición de Protocols en Swift

En otros lenguajes de programación no los llaman protocols, los llaman interfaces, que es algo similar a eso. Se define tan sencillo como poner Protocol y el nombre del protocol. El nombre del protocol siempre iniciando con mayúscula y los protocols en Swift pueden ser adoptados por classes, structs y enums. En cuanto a los requerimientos que un protocolo define es tan sencillo como por ejemplo si quieres que un protocolo especifique una propiedad, la tienes que poner que es “var”, nombre de la propiedad, el tipo y ya si es un get o un set o los dos, ahí tienes que especificar un poco el tipo de propiedad que va hacer.

También se puede especificar en un Protocol los init de una clase, struct o enum.

En Swift los protocolos son tratados como cualquier otro Tipo: puedes definir tu protocolo como si fuera un tipo normal, una clase o cualquier otra entidad y esto es muy útil.  Uno de los ejemplos más clásicos de programación y protocolos sobre esto suele ser el típico de protocol Animal, que tiene ciertas características y luego tienes tus clases, tu clase de Perro diferente a tu protocolo animal, tu clase de Gato diferente a tu protocolo animal y lo que quieres es tener un array que contenga Gatos y Perros entonces puedes hacer una array tipo Animal donde puedes meter a ambos, etc.

Es una de las grandes ventajas que te ofrece tener un protocolo, tener algo en común que sabes que es, sabes que métodos tiene y puedes construir a array de tipos mixtos que al final son objetos que conforman a un protocolo común.

Otro ejemplo clásico de protocolos es la delegación, es un patrón muy común en programación en iOS. Si vemos se utiliza para todo tipo de cosas como collectionViews y tableViews que tiene delegates, digamos que una forma para definir las acciones de algo que está delegando a una clase es simplemente utilizar un protocolo.

Adoptar un protocolo en una Extension

Podemos adoptar un protocolo a una clase simplemente en su definición: class Perro implementa al protocolo Animal pero otras de las formas que hay en Swift y que también es común para tener el código más limpio y estructurado es adoptar protocolos en las extensiones de las clases de. Esto es algo importante en el tema de organización e implementar un código.

Herencia y composición de Protocols en Swift

En cuanto a la herencia de los protocolos, se podría extender la funcionalidad de un protocolo y eso ayuda mucho porque puedes hacer cosas genéricas. Por ejemplo, digamos que un elemento no tan genérico te permite navegar, digamos que tiene funciones específicas como ir a la cuenta o ir a otras partes de la aplicación y ya después tenemos cosas que son genéricas que ya son para hacer un pop(), un present(…), etc. Esto es un ejemplo interesante cuando estas manejando navegación, es decir la idea es que para reutilizar código, definimos un protocolo y después otros protocolos que heredan esa funcionalidad y nos ahorramos tener que volver a implementarla.

Hablando de herencia, automáticamente siempre se habla se composition. Y es otras de las cosas que los protocolos nos permiten hacer: Que una clase con clase adopte varios protocolos. Una cosa interesante en esa parte es que si estas implementando un método simplemente con el  “&” puedes decir: este parámetro que estoy recibiendo para implementar este método, me va a implementar este y este protocolo. Esto no se podía hacer antes en Swift ya que antes solo podías definir un tipo. Por ejemplo: tengo el protocolo Nombre y el protocolo Apellido. Se pasa una Persona, y está implementando ambos protocolos. Al pasarlo y definirlo con el “&” puedes sacar el Nombre y el Apellido de esa persona sin necesidad de saber los otros parámetros (suponiendo que adoptando ambos parametros obtienes ambas propiedades)

Relacionado con esto también es importante decir que en Swift tenemos varias formas de comprobar el tipo de protocolo que tenemos o quien está conformando este protocolo que es parecido a como se hacen los check de clases con los operadores.

Protocolos con opcionales

Un tema importante pero que no es muy usado ahora pero que era muy usado, es el tema de definir parametros y funciones opcionales en un protocolo. Todavía se puede hacer, lo puedes definir, simplemente es agregar la palabra @objc en frente del protocolo y puedes definir simplemente en frente del método @opcional y eso te da la misma implementación que tenías antes en Objective-C. Ahora mismo en Swift se trata de evitar porque al convertir un protocolo a Objective-C para hacer cierto parametro o función opcional, lo que hacemos es que el protocolo deja de ser un protocolo Swift y pasa hacer un protocolo Objective-C y eso tiene una desventaja: Los protocolos Swift se pueden aplicar a clases, struct o enums… pero los protoclos Objective-C solo se pueden aplicar a clases.

Una alternativa es definir un protocolo con los requerimientos mínimos obligatorios, y si veo que algo es opcional o hay algo que no todo el mundo va a implementar, haría un segundo protocolo con es única funcionalidad y ya jugaría con la composición, el que lo necesite implementa los dos y el que no solo implementa uno.

Default Implementations

Ya por último, el tema de protocol extensions, nos permite primero que todo definir comportamientos genéricos por default, donde podemos definir por ejemplo: “Abrir puerta” que se abre de izquierda a derecha, por cualquier razón tienes una puerta giratoria que no es de esa forma, entonces la implementación genérica es que se va abrir de izquierda a derecha, entonces ya empiezas a extender su funcionalidad de que es una puerta giratoria donde puedes implementar y poner algo específico. De cara a reusar código y acortar tiempo de desarrollo, las definiciones por defecto de un método de protocol extensions, que para eso son, defines un protocolo y ahí mismo puedes definir el defult behaviour que va a tener un parámetro o una función del protocolo, todo lo que definas ahí si es una clase o un struct, implementas el protocolo y no se implementa nada más se hereda ese código. Si la clase o el stuct hacen una implementación propia, pues hace un override y se utiliza esa, pero es súper útil para heredar “partes de codigo”.

Ahora ya por ultimo hablaremos de añadir constraints a los protocols y a sus extensiones. Este tema es muy útil y especifico: Cuando quieres extender algo pero solo para ciertos tipos. Hay un tema que te ayuda hacer el código más conciso, es el tema de reuse Identifier: por ejemplo en collectionViews  o tableViews.

Associated types y Protocolos

Antes de acabar quería comentar otro tema que es los protocolos con associated types, porque es algo que las primeras es complicado. Y con esto me refiero dentro de un protocolo defines un associated type para utilizarlo. Por ejemplo: Protocol Animal -> dentro defines un associated type, que es “Vertebrado” y ya en las funciones que defines al protocolo utilizas el tipo Vertebrado. Esto es algo que en principio cuando empecé a usar Swift no conocía mucho y después tenía muchos problemas cuando usaba ese protocolo como un tipo dentro del código. Esto no está permitido en ahora; Va a estar permitido a futuro. Ahora mismo cuando defines un associated type dentro de un protocolo, o un requerimiento Self, ese protocolo ya no se puede usar como tipo dentro de tu cogido, y el ejemplo más claro de esto es protocolos como Equatable: En cuento defines Equatable a una clase, clase A Equatable, clase B Equatable, tú no puedes crear una array de Equatables y meter A’s y B’s dentro, porque son diferentes, no son el mismo objeto, no puedes hacer objeto A igual a objeto B aunque son Equatable los dos. Sucede porque el protocolo tiene un requerimiento Self ->  Es un requerimiento del propio protocolo, entonces cualquier protocolo que tenga Self o associated type en su definición no se puede usar como tipos es una cosa totalmente diferente.

Deja un comentario