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:
No puede usar una instrucción
break
ocontinue
para salir de la llamada actual del cierre delbody
ni omitir las llamadas subsiguientes.El uso de la declaración de
return
en el cierre delbody
saldrá solo de la llamada albody
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.
-
break
/continue
solo trabajar en unfor .. in
-
return
enforEach
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)
}
}
}