Programación Orientada a Protocolos en Swift 2

Introducción

Con el lanzamiento de Swift 2, Apple agregó una serie de nuevas características y capacidades al lenguaje de programación Swift. Uno de los más importantes, sin embargo, fue una revisión de los protocolos. La funcionalidad mejorada disponible con los protocolos Swift permite un nuevo tipo de programación, programación orientada al protocolo. Esto contrasta con el estilo de programación orientado a objetos más común al que muchos de nosotros estamos acostumbrados.

En este tutorial, les mostraré los conceptos básicos de la programación orientada a protocolos en Swift y en qué se diferencia de la programación orientada a objetos..

Prerrequisitos

Este tutorial requiere que estés ejecutando Xcode 7 o superior, que incluye soporte para la versión 2 del lenguaje de programación Swift.

1. Conceptos básicos del protocolo

Si aún no está familiarizado con los protocolos, son una forma de ampliar la funcionalidad de una clase o estructura existente. Un protocolo puede considerarse como un plano o una interfaz que define un conjunto de propiedades y métodos. Se requiere una clase o estructura que se ajuste a un protocolo para completar estas propiedades y métodos con valores e implementaciones respectivamente.

También se debe tener en cuenta que cualquiera de estas propiedades y métodos se pueden designar como opcionales, lo que significa que no se requieren los tipos conformes para implementarlos. Una definición de protocolo y conformidad de clase en Swift podría verse así:

protocolo Bienvenido var welcomeMessage: String get set opcional func welcome () class Bienvenida: Bienvenido var welcomeMessage = "¡Hola mundo!" func welcome () print (welcomeMessage)

2. Un ejemplo

Para comenzar, abra Xcode y cree una nueva área de juegos para iOS o OS X. Una vez que Xcode haya creado la zona de juegos, reemplace su contenido con lo siguiente:

protocol Drivable var topSpeed: Int get protocol Reversible var reverseSpeed: Int get protocol Transport var seatCount: Int get

Definimos tres protocolos, cada uno contiene una propiedad. A continuación, creamos una estructura que se ajusta a estos tres protocolos. Agregue el siguiente código al patio de recreo:

estructura Automóvil: manejable, reversible, transporte var topSpeed ​​= 150 var reverseSpeed ​​= 20 var seatCount = 5

Es posible que haya notado que, en lugar de crear una clase que se ajuste a estos protocolos, creamos una estructura. Hacemos esto para evitar uno de los problemas típicos inherentes a la programación orientada a objetos., referencias de objetos.

Imagina, por ejemplo, que tienes dos objetos, A y B. A crea algunos datos por sí mismo y mantiene una referencia a esos datos. A luego comparte estos datos con B por referencia, lo que significa que ambos objetos tienen una referencia al mismo objeto. Sin A sabiendo, B cambia los datos de alguna manera..

Si bien esto puede no parecer un gran problema, puede ser cuando A no esperaba que los datos se alteraran. El objeto A puede encontrar datos que no sabe cómo manejar o manejar. Este es un riesgo común de referencias de objetos..

En Swift, las estructuras pasan. valor en lugar de por referencia. Esto significa que, en el ejemplo anterior, si los datos creados por A se empaquetaron como una estructura en lugar de un objeto y se compartieron con B, los datos se copiarían en lugar de compartirlos por referencia. Esto daría lugar a que tanto A como B tuvieran su propia copia única de la misma pieza de datos. Un cambio realizado por B no afectaría la copia administrada por A.

Rompiendo el ManejableReversible, y Transporte Los componentes en protocolos individuales también permiten un mayor nivel de personalización que la herencia de clase tradicional. Si ha leído mi primer tutorial sobre el nuevo marco GameplayKit en iOS 9, este modelo orientado a protocolos es muy similar a la estructura de Entidades y Componentes utilizada en el marco GameplayKit..

Al adoptar este enfoque, los tipos de datos personalizados pueden heredar la funcionalidad de múltiples fuentes en lugar de una sola superclase. Teniendo en cuenta lo que tenemos hasta ahora, podríamos crear las siguientes clases:

  • una clase con componentes de la ManejableReversible protocolos
  • una clase con componentes de la Manejable y Transportable protocolos
  • una clase con componentes de la ReversibleTransportable protocolos

Con la programación orientada a objetos, la forma más lógica de crear estas tres clases sería heredar de una superclase que contiene los componentes de los tres protocolos. Sin embargo, este enfoque hace que la superclase sea más complicada de lo que debe ser y cada una de las subclases hereda más funcionalidad de la que necesita..

3. Extensiones de protocolo

Todo lo que les mostré hasta ahora ha sido posible en Swift desde su lanzamiento en 2014. Estos mismos conceptos orientados al protocolo podrían incluso aplicarse a los protocolos de Objective-C. Sin embargo, debido a las limitaciones que solían existir en los protocolos, la verdadera programación orientada a protocolos no fue posible hasta que se agregaron varias funciones clave al lenguaje Swift en la versión 2. Una de las características más importantes es extensiones de protocolo, incluso extensiones condicionales.

En primer lugar, extendamos la Manejable protocolo y agregar una función para determinar si un determinado Manejable es mas rapido que otro Agregue lo siguiente a su área de juegos:

extensión Drivable func isFasterThan (item: Drivable) -> Bool return self.topSpeed> item.topSpeed let sedan = Car () let sportsCar = Car (topSpeed: 250, reverseSpeed: 25, seatCount: 2) sedan.isFasterThan (coche deportivo)

Se puede ver que, cuando se ejecuta el código del patio de recreo, genera un valor de falsocomo tu sedán el coche tiene un valor predeterminado velocidad máxima de 150, que es menor que el coche deportivo.

Es posible que hayas notado que proporcionamos una función. definición en lugar de una función declaración. Esto parece extraño, porque se supone que los protocolos solo contienen declaraciones. ¿Derecha? Esta es otra característica muy importante de las extensiones de protocolo en Swift 2, comportamientos por defecto. Al extender un protocolo, puede proporcionar una implementación predeterminada para funciones y propiedades computadas para que las clases que se ajusten al protocolo no tengan que.

A continuación vamos a definir otra. Manejable extensión de protocolo, pero esta vez solo la definiremos para los tipos de valor que también se ajustan a la Reversible protocolo. Esta extensión contendrá una función que determina qué objeto tiene el mejor rango de velocidad. Podemos lograr esto con el siguiente código:

extensión Conducible donde Auto: Reversible func hasLargerRangeThan (item: Self) -> Bool return (self.topSpeed ​​+ self.reverseSpeed)> (item.topSpeed ​​+ item.reverseSpeed) sportsCar.hasLargerRangeThan (sedan)

los Yo La palabra clave, escrita con una "S" mayúscula, se utiliza para representar la clase o estructura que se ajusta al protocolo. En el ejemplo anterior, el Yo palabra clave representa la Coche estructura.

Después de ejecutar el código del área de juegos, Xcode mostrará los resultados en la barra lateral a la derecha, como se muestra a continuación. Tenga en cuenta que coche deportivo tiene un rango mayor que sedán.

4. Trabajar con la biblioteca estándar de Swift

Mientras que definir y extender sus propios protocolos puede ser muy útil, el verdadero poder de las extensiones de protocolo se muestra cuando se trabaja con la biblioteca estándar de Swift. Esto le permite agregar propiedades o funciones a los protocolos existentes, como CollectionType (usado para cosas como arrays y diccionarios) y Equiparable (poder determinar cuando dos objetos son iguales o no). Con las extensiones de protocolo condicional, también puede proporcionar una funcionalidad muy específica para un tipo específico de objeto que se ajusta a un protocolo.

En nuestro patio de recreo, vamos a extender el CollectionType Protocolo y cree dos métodos, uno para obtener la velocidad máxima promedio de los automóviles en una Coche Array y otro para la velocidad inversa media. Agregue el siguiente código a su área de juegos:

extensión CollectionType donde Self.Generator.Element: Drivable func averageTopSpeed ​​() -> Int var total = 0, count = 0 para el elemento en self total + = item.topSpeed ​​count ++ return (total / count) func averageReverseSpeed(elementos: T) -> Int var total = 0, count = 0 para item en items total + = item.reverseSpeed ​​count ++ return (total / count) let cars = [Car (), sedan, sportsCar] cars .averageTopSpeed ​​() averageReverseSpeed ​​(cars)

La extensión del protocolo que define la averageTopSpeed El método aprovecha las extensiones condicionales en Swift 2. Por el contrario, el mediaReverseSpeed La función que definimos directamente debajo es otra forma de lograr un resultado similar utilizando los genéricos Swift. Yo personalmente prefiero el aspecto más limpio CollectionType extensión del protocolo, pero depende de las preferencias personales.

En ambas funciones, iteramos a través de la matriz, sumamos la cantidad total y luego devolvemos el valor promedio. Tenga en cuenta que mantenemos manualmente un recuento de los elementos de la matriz, ya que al trabajar con CollectionType en lugar de regular Formación escribir elementos, el contar la propiedad es un Self.Index.Distance escriba el valor en lugar de una En t.

Una vez que su área de juegos haya ejecutado todo este código, debería ver una velocidad máxima promedio de salida de 183 y una velocidad inversa media de 21.

5. Importancia de las clases.

A pesar de que la programación orientada a protocolos es una forma muy eficiente y escalable de administrar su código en Swift, todavía hay razones perfectamente válidas para usar clases cuando se desarrolla en Swift:

Compatibilidad al revés

La mayoría de los SDK de iOS, watchOS y tvOS están escritos en Objective-C, utilizando un enfoque orientado a objetos. Si necesita interactuar con cualquiera de las API incluidas en estos SDK, se le obliga a utilizar las clases definidas en estos SDK..

Hacer referencia a un archivo externo o elemento

El compilador Swift optimiza la vida útil de los objetos en función de cuándo y dónde se utilizan. La estabilidad de los objetos basados ​​en clases significa que sus referencias a otros archivos y elementos permanecerán consistentes.

Referencias de objetos

Las referencias a objetos son exactamente lo que necesita a veces, por ejemplo, si está enviando información a un objeto en particular, como un renderizador de gráficos. El uso de clases con uso compartido implícito es importante en situaciones como esta, porque debe asegurarse de que el renderizador al que está enviando los datos sigue siendo el mismo que antes..

Conclusión

Esperamos que al final de este tutorial pueda ver el potencial de la programación orientada a protocolos en Swift y cómo se puede usar para simplificar y ampliar su código. Si bien esta nueva metodología de codificación no reemplazará por completo la programación orientada a objetos, trae una serie de posibilidades nuevas y muy útiles..

Desde los comportamientos predeterminados hasta las extensiones de protocolo, la programación orientada a protocolos en Swift será adoptada por muchas API futuras y cambiará por completo la forma en que pensamos sobre el desarrollo de software..

Como siempre, asegúrese de dejar sus comentarios y sugerencias en los comentarios a continuación.