switch style statement removed over loop has game for example been swift loops foreach sequence for-in-loop

swift - style - ¿Cuándo usar forEach(_:) en lugar de for in?



switch swift example (3)

Hace poco me encontré con un caso de uso en el que usar forEach era preferible de una manera tangible que para for in . Digamos que desea eliminar todas las subcapas de una capa. Una declaración como la siguiente no funciona, ya que necesita desenvolver el [CALayer]

for layer in self.videoContainerView.layer.sublayers!

Si las subcapas son nulas, obtendrá un bloqueo. Esto te obliga a comprobar si hay subcapas primero. Sin embargo, un forEach hace esto mucho más simple como en el siguiente:

self.videoContainerView.layer.sublayers?.forEach { $0.removeFromSuperlayer() }

Como se documenta en Array y Dictionary forEach(_:) Métodos de instancia:

Llama al cierre dado en cada elemento de la secuencia en el mismo orden que un bucle for-in.

Sin embargo, adaptado de la descripción de la secuencia :

Una secuencia es una lista de valores que puede recorrer uno por uno. La forma más común de iterar sobre los elementos de una secuencia es usar un bucle for-in .

Implicando esa secuencia de iteración por forEach(_:) o for in :

let closedRange = 1...3 for element in closedRange { print(element) } // 1 2 3 closedRange.forEach { print($0) } // 1 2 3

O (Array):

let array = [1, 2, 3] for element in array { print(element) } // 1 2 3 array.forEach { print($0) } // 1 2 3

Daría la misma salida.

¿Por qué forEach(_:) incluso existe? es decir, ¿cuál es el beneficio de usarlo en lugar del bucle for in ? ¿Serían los mismos desde la vista del punto de rendimiento?

Como suposición, podría ser un azúcar sintáctico, especialmente cuando se trabaja con programación funcional .


No hay beneficio de rendimiento ofrecido por forEach . De hecho, si observa el código fuente , la función forEach realidad simplemente se desempeña for - in . Para las compilaciones de lanzamiento, la sobrecarga de rendimiento de esta función sobre el simple uso de for - in yourself es irrelevante, aunque para las compilaciones de depuración, se produce un impacto observable en el rendimiento.

La principal ventaja de forEach es que cuando realiza la programación funcional, puede agregarla a una cadena de llamadas funcionales, sin tener que guardar el resultado anterior en una variable separada que necesitaría si la usara in sintaxis. Entonces, en lugar de:

let objects = array.map { ... } .filter { ... } for object in objects { ... }

En su lugar, puede permanecer dentro de los patrones de programación funcional:

array.map { ... } .filter { ... } .forEach { ... }

El resultado es un código funcional que es más conciso con menos ruido sintáctico.

FWIW, la documentación para Array , Dictionary y Sequence nos recuerdan las limitaciones introducidas por forEach , a saber:

  1. No puede usar una instrucción break o continue para salir de la llamada actual del cierre del body ni omitir las llamadas subsiguientes.

  2. El uso de la declaración de return en el cierre del body saldrá solo de la llamada al body actual, no de ningún ámbito externo, y no se salteará las llamadas posteriores.


Son más o menos intercambiables, pero hay dos diferencias importantes.

  1. break / continue solo trabajar en un for .. in
  2. return en forEach saldrá del cierre, pero no detendrá la iteración.

La razón de esto es que for .. in es una forma especial en el idioma (que permite romper y continuar trabajando como se espera). Es algo que no se puede implementar de manera idéntica utilizando el lenguaje en sí.

Sin embargo, forEach no es una forma especial y se puede volver a implementar de forma idéntica al escribirla como una función.

extension Sequence { func myOwnForEach(_ body: (Self.Element) throws -> Void) rethrows { let it = Self.makeIterator() while let item = it.next() { body(item) } } }