Swift funcional: Cierres { }

Créditos: Pexels

Los cierres son bloques de funcionalidad autónomos que se pueden transmitir y utilizar en el código.

— Apple

Los cierres pueden capturar y almacenar referencias a cualquier constante y variable del contexto en el que se definen, lo que se conoce como cierre, por lo tanto, Cierre. Puede pensar en un cierre como una función que no tiene un nombre propio y captura los valores de su entorno. Las funciones y los cierres son objetos de primera clase en Swift: puede almacenarlos, pasarlos como argumentos a funciones y tratarlos como lo haría con cualquier otro valor u objeto. Pasar cierres como controladores de finalización es un patrón común en muchas API. La biblioteca Swift estándar utiliza cierres principalmente para el manejo de eventos y devoluciones de llamada.

Las funciones son fragmentos de código autónomos que realizan una tarea específica. A una función se le da un nombre que identifica lo que hace, y este nombre se usa para «llamar» a la función para que realice su tarea cuando sea necesario. Se define una función con la palabra clave func. Funciones puede tomar ninguno a muchos parámetros, variadic parámetros y devolver ninguno o varios parámetros.

La función toma 2 parámetros y devuelve 1 parámetro

Tipos de función

El tipo de función se compone de los tipos de parámetros y el tipo de retorno de la función. Para el ejemplo anterior, el tipo de función es:(Int, Int) -> Int

Esto se puede leer como: «Una función que tiene dos parámetros, ambos de tipo Int y que devuelve un valor de tipo Int.»El tipo de función se puede establecer como parámetro o tipo de función de retorno.

Los tipos de función se pueden asignar a cualquier variable como esta:

var mathFunction: (Int, Int) -> Int = add

Las funciones son casos especiales de cierres. Los cierres adoptan una de tres formas:

  • Funciones globales: Tienen un nombre y no pueden capturar el valor.
  • Funciones anidadas: Tienen un nombre y pueden capturar valores de la función que las encierra.
  • Expresiones de cierre: No tienen nombre y pueden capturar valores de su contexto circundante.

Expresión de cierre:

Documento de cierre rápido

El cierre se puede crear colocando un tipo de función dentro de llaves y una palabra clave in después del tipo de retorno.

Nombres de argumento abreviados

Los argumentos de cierre pueden referirse a una posición, p. ej. , , , y así sucesivamente.

Después de especificar nombres abreviados, no es necesario especificar argumentos de cierre y en keyword

Retornos implícitos de Closure:

Los cierres de expresión única pueden devolver implícitamente el resultado de su expresión única omitiendo la palabra clave return de su declaración.

Para un cierre de expresión multilínea, no se puede omitir la palabra clave return.

Cierre de arrastre:

Si necesita pasar una expresión de cierre a una función como último argumento de la función y la expresión de cierre es demasiado larga, se puede escribir como cierre final. Un cierre final se escribe después de los paréntesis () de la llamada a la función, aunque sigue siendo un argumento de la función. Cuando se utiliza la sintaxis de cierre final, no se escribe la etiqueta de argumento para el cierre como parte de la llamada a la función.

Cierre como un argumento de la llamada al método

Trailing Cierre (es decir, cierre después de paréntesis de método)

Si el cierre es el último parámetro de un método, swift le permite escribir de esta manera 🖕

Ejemplo de cierre final usando reducir()

El uso de la sintaxis de cierre final encapsula cuidadosamente la funcionalidad del cierre inmediatamente después de la función que admite el cierre, sin necesidad de envolver todo el cierre dentro de los paréntesis exteriores del método reduce(_:).

Captura de valores:

Un cierre puede capturar constantes y variables del contexto circundante en el que se define. El cierre puede hacer referencia y modificar los valores de esas constantes y variables desde dentro de su cuerpo, incluso si el ámbito original que definió las constantes y variables ya no existe.

En Swift, la forma más simple de un cierre que puede capturar valores es una función anidada, escrita dentro del cuerpo de otra función. Una función anidada puede capturar cualquiera de los argumentos de su función externa y también puede capturar cualquier constante y variable definida dentro de la función externa.

Ejemplo dado en el documento Swift

Esta función makeIncrementer acepta un argumento, es decir, Int, como entrada y devuelve un tipo de función, es decir, () -> Int. Esto significa que devuelve una función, en lugar de un valor simple. La función que devuelve no tiene parámetros, y devuelve un valor Int cada vez que se llama.

Aquí amount es el argumento, runningTotal se declara como variable y se inicializa con 0. La función anidada incrementer captura amount y runningTotal del contexto circundante.

Vamos a ver makeIncrementer en acción:

Nota: Como optimización, Swift puede capturar y almacenar una copia de un valor si ese valor no está mutado por un cierre y si el valor no está mutado después de crear el cierre.

Swift también se encarga de toda la gestión de memoria que implica la eliminación de variables cuando ya no son necesarias.

Para deshacerse de la expresión de cierre largo en el argumento de función, puede usar typealias.

Cierres sin escape:

Los parámetros de cierre se escapaban de forma predeterminada antes de Swift 3. Un cierre no escaparía al cuerpo de la función si los parámetros de cierre están marcados como sin escape

En Swift 3 se ha invertido. Cuando pasa un cierre como argumento de función, el cierre se ejecuta con el cuerpo de la función y devuelve el compilador. A medida que la ejecución termina, el cierre pasado se sale del alcance y no tiene más existencia en la memoria.

Lo menos que necesita Saber

Los parámetros de cierre no se escapan de forma predeterminada, si desea escapar de la ejecución de cierre, debe usar @ escaping con los parámetros de cierre.

Ciclo de vida del cierre sin escape:
1. Pase el cierre como argumento de función, durante la llamada a la función.
2. Haga un poco de trabajo en función y luego ejecute el cierre.
3. Devuelve la función.

Debido a una mejor gestión y optimización de la memoria, Swift ha cambiado todos los cierres para que no se escapen de forma predeterminada. CaptureList.swift es un ejemplo de cierre sin escape.

Nota: la anotación @sin escape se aplica solo a tipos de función

Cierres de escape:

Se dice que un cierre escapa de una función cuando el cierre se pasa como argumento a la función, pero se llama después de que la función regresa. Marcar un cierre con @escaping significa que debe hacer referencia explícita a self dentro del cierre.

Ciclo de vida del cierre @ escaping:
1. Pase el cierre como argumento de función, durante la llamada a la función.
2. Haga algún trabajo adicional en función.
3. Función ejecutar el cierre de forma asíncrona o almacenada.
4. Devuelve la función.

Veamos dónde se escapan los cierres por defecto:

  • Las variables de tipo de función son de escape implícito
  • Las variantes de tipo son de escape implícito
  • Los cierres opcionales son de escape implícito

Error común:

Asignar un cierre sin escape al cierre de escape. Hay 2 maneras de arreglar esto:

  • Marque el cierre como escape
  • O mantenga el comportamiento predeterminado @noescape haciendo que el cierre sea opcional

Autoclosures:

El atributo @autoclosure de Swift le permite definir un argumento que se envuelve automáticamente en un cierre. No toma ningún argumento, y cuando se llama, devuelve el valor de la expresión que está envuelta dentro de ella. Esta conveniencia sintáctica le permite omitir llaves alrededor del parámetro de una función escribiendo una expresión normal en lugar de un cierre explícito.

Por ejemplo, la función assert(condition:message:file:line:) toma un autoclosure para sus parámetros condition y message; su parámetro condition solo se evalúa en compilaciones de depuración y su parámetro message solo se evalúa si conditiones false.

func assert(_ expression: @autoclosure () -> Bool,
_ message: @autoclosure () -> String) {}

Para usar @autoclosure con @escaping la sintaxis de atributo es:

@autoclosure @escaping () -> Bool

Cierres vs Bloques:

» Los cierres rápidos y los bloques de Objective-C son compatibles para que pueda pasar cierres rápidos a métodos de Objective-C que esperan bloques. Los cierres y funciones Swift tienen el mismo tipo, por lo que incluso puede pasar el nombre de una función Swift. Los cierres tienen una semántica de captura similar a la de los bloques, pero difieren en una forma clave: las variables son mutables en lugar de copiadas. En otras palabras, el comportamiento de _ _ block en Objective-C es el comportamiento predeterminado para las variables en Swift.»

Cierres vs Delegados:

La solución depende del problema. Además, Apple está cambiando su enfoque al patrón de devolución de llamada. UIAlertAction es un ejemplo de esto.

https://medium.com/@abhimuralidharan/functional-swift-all-about-closures-310bc8af31dd

https://medium.com/@kumarpramod017/what-do-mean-escaping-and-nonescaping-closures-in-swift-d404d721f39d

https://oleb.net/blog/2016/10/optional-non-escaping-closures/

https://swiftunboxed.com/lang/closures-escaping-noescape-swift3/

https://medium.com/@johnsundell/using-autoclosure-when-designing-swift-apis-67fe20a8b2e

Deja una respuesta

Tu dirección de correo electrónico no será publicada.

Previous post Pensamientos sobre Calentadores de Establo de Caballos-Blackburn Architects, P. C. : Blackburn Architects, P. C.
Next post Garantía