我正在尝试在完成UIView动画后打破for循环。以下是以下片段:
public func greedyColoring() {
let colors = [UIColor.blue, UIColor.green, UIColor.yellow, UIColor.red, 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
}
}
})
}
}
}
}
基本上这个方法迭代一个Graph并检查每个顶点及其邻居,并给顶点一个颜色,它的邻居都没有。这就是为什么它必须打破未使用的第一种颜色的迭代。我尝试使用Unlabeled
循环但它仍然无法编译(break is only allowed inside a loop
)。问题是我想要想象哪些颜色已经过测试。这就是为什么我使用UIView.animate()
有没有解决我的问题?
答案 0 :(得分:4)
您需要了解,传递给animate函数的完成块在动画完成后被称为,这在for循环迭代后很长一段时间(在计算机时间内)通过颜色数组。您将持续时间设置为1秒,这意味着完成将在1秒后调用。由于for循环不等待你的动画完成,所以它们都将同时开始动画(也许会偏离几毫秒)。 for循环在动画完成之前已完成,这就是为什么打破for循环没有意义,因为它不再运行了!
如果您希望在调用print("Fire")
函数之前添加UIView.animate
调用,并在完成块中添加print("Finished")
。在控制台中,您应该在所有完成之前看到所有 fire 。
您应该对动画进行排队,以便它们一个接一个地开始和结束。
答案 1 :(得分:2)
正如弗雷德里克所说,动画中你的for循环中下一个执行顺序与你的完成顺序不同步。这意味着无论您的块实现如何,for循环都将保持循环。 一个简单的解决方法是使用CABasicAnimation和CAAnimationGroup创建动画。因此,for循环的产品将是一组动画组中的动画链。
本教程将为您提供有关如何使用CABasicAnimation和CAAnimationGroup的建议:https://www.raywenderlich.com/102590/how-to-create-a-complex-loading-animation-in-swift
您可以使用此方法,因为断开for循环的条件由不依赖于动画本身的参数给出。一旦动画附加到您试图制作动画的视图,动画就会被执行。
希望这有帮助。
答案 2 :(得分:1)
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)
答案 3 :(得分:-1)
如前所述,完成块都是异步调用的,因此在for循环中不存在。最好的办法是在完成块中调用一个常用方法,它会在第一次调用后忽略所有内容。
var firstMatch: UIColor?
func foundMatch (_ colour: UIColor)
{
if firstMatch == nil
{
firstMatch = colour
print (firstMatch?.description ?? "Something went Wrong")
}
}
let colours: [UIColor] = [.red, .green, .blue]
for colour in colours
{
UIView.animate(withDuration: 1.0, animations: {}, completion:
{ (success) in
if success { foundMatch (colour) }
})
}