Romper un bucle dentro de un bloque de animation

Estoy intentando romper un bucle forzado después de completar una animation UIView. Aquí está el siguiente fragment:

public func greedyColoring() { let colors = [UIColor.blue, UIColor.green, UIColor.yellow, UIColor.networking, UIColor.cyan, UIColor.orange, UIColor.magenta, UIColor.purple] for vertexIndex in 0 ..< self.graph.vertexCount { let neighbours = self.graph.neighborsForIndex(vertexIndex) let originVertex = vertices[vertexIndex] print("Checking now Following neighbours for vertex \(vertexIndex): \(neighbours)") var doesNotMatch = false while doesNotMatch == false { inner: for color in colors{ UIView.animate(withDuration: 1, delay: 2, options: .curveEaseIn, animations: { originVertex.layer.backgroundColor = color.cgColor }, completion: { (complet) in if complet { let matches = neighbours.filter { let vertIdx = Int($0)! print("Neighbour to check: \(vertIdx)") let vertex = self.vertices[vertIdx-1] if vertex.backgroundColor == color{ return true }else{ return false } } //print("there were \(matches.count) matches") if matches.count == 0 { // do some things originVertex.backgroundColor = color doesNotMatch = true break inner } else { doesNotMatch = false } } }) } } } } 

Básicamente, este método itera sobre un gráfico y comtesting cada vértice y sus vecinos y le da al vértice un color que ninguno de sus vecinos tiene. Es por eso que tiene que romper la iteración en el primer color que no se ha utilizado. Traté de usar loops Unlabeled pero todavía no comstack (el break is only allowed inside a loop ). El problema es que me gustaría visualizar qué colors se han probado. Es por eso que estoy usando UIView.animate()

¿Hay alguna forma de resolver mi problema?

Debe comprender que el bloque de finalización que pasa a la function animada se invoca después de que la animation haya finalizado, lo cual es mucho time (en el time de la computadora) después de que su ciclo for haya iterado a través de la matriz de colors. Establece que la duración sea de 1 segundo, lo que significa que la finalización se llama 1 segundo más tarde. Dado que el bucle for no está esperando a que finalice su animation, todos comenzarán a animar al mismo time (quizás en algunos milisegundos). El bucle for se completó mucho antes de que se completara la animation, por lo que no tiene sentido romper el bucle for, ¡ya que no se está ejecutando!

Si desea ver esto, agregue una llamada de print("Fire") justo antes de UIView.animate function UIView.animate e print("Finished") en el bloque de finalización. En la console, deberías ver todo el fuego antes de terminar .

En su lugar, debe poner en queue las animaciones, para que comiencen y terminen una tras otra.

Como mencionó Fnetworkingerik, las animaciones el order en la ejecución del siguiente en su bucle for no es sincrónico con el order de sus completaciones. Esto significa que el bucle for mantendrá el ciclo sin importar las implementaciones de bloques. Una solución fácil sería crear las animaciones mediante CABasicAnimation y CAAnimationGroup. Para que el producto de tu bucle for fuera una cadena de animaciones astackdas en un grupo de animation.

Este tutorial le dará una idea de cómo usar CABasicAnimation y CAAnimationGroup: https://www.raywenderlich.com/102590/how-to-create-a-complex-loading-animation-in-swift

Puede usar este enfoque, porque la condición para romper su ciclo for está dada por parameters que no dependen de la animation misma. Las animaciones se ejecutarán de todos modos una vez que se adjunten a la vista que intentas animar.

Espero que esto ayude.

 Just modifying your code a little bit. Its a old school recursion but should work. Assuming all the instance variables are available here is a new version. public func greedyColoring(vertex:Int,colorIndex:Int){ if vertexIndex > self.graph.vertexCount { return } if colorIndex > color.count {return} let neighbours = self.graph.neighborsForIndex(vertexIndex) let originVertex = vertices[vertexIndex] let color = self.colors[colorIndex] UIView.animate(withDuration: 1, delay: 2, options: .curveEaseIn, animations: { originVertex.layer.backgroundColor = color.cgColor }, completion: { (complet) in if complet { let matches = neighbours.filter { let vertIdx = Int($0)! print("Neighbour to check: \(vertIdx)") let vertex = self.vertices[vertIdx-1] //No idea what you are trying to do here. So leaving as it is. if vertex.backgroundColor == color{ return true }else{ return false } } //print("there were \(matches.count) matches") if matches.count == 0 { // do some things originVertex.backgroundColor = color greedyColoring(vertex: vertex++,colorIndex:0) } else { greedyColoring(vertex: vertex,colorIndex: colorIndex++) } } }) } Now we can call this function simply greedyColor(vertex:0,colorIndex:0) 

Como se mencionó anteriormente, los bloques de finalización se denominan todos asincrónicamente y, por lo tanto, no existen dentro del bucle for. Su mejor opción es llamar a un método común desde dentro de los bloques de finalización que ignorará todo después de la primera llamada.

 var firstMatch: UIColor? func foundMatch (_ colour: UIColor) { if firstMatch == nil { firstMatch = colour print (firstMatch?.description ?? "Something went Wrong") } } let colours: [UIColor] = [.networking, .green, .blue] for colour in colours { UIView.animate(withDuration: 1.0, animations: {}, completion: { (success) in if success { foundMatch (colour) } }) }