Swift逆向循环异常:闭包内代码为何正向执行?
Swift代码执行顺序问题分析与解决
问题代码
fileprivate func genericNodeWalker(_ direction:Follow, encapsulatedMethod: @escaping (_ iNode:Int) -> Void) { switch direction { case .forwards: for nodeIndex in 0..<self.nodes.count { encapsulatedMethod(nodeIndex) } case .backwards: for indexNode in stride(from: self.nodes.count - 1, through: 0, by: -1) { // for nodeIndex in (0..<self.nodes.count).reversed() { print("indexNode \(indexNode)") encapsulatedMethod(indexNode) } } } fileprivate func fadeOutNodes2() { genericNodeWalker(.backwards) { index2D in let wait = SKAction.wait(forDuration: Double(index2D) * 2) let custom = SKAction.run { print("index2D \(index2D)") } let sequence = SKAction.sequence([wait,custom]) self.nodes[index2D].run(sequence) } }
问题现象
指定以逆向方式遍历节点时,控制台打印的indexNode是逆向顺序(6→0),但fadeOutNodes2闭包内SKAction.run里打印的index2D却是正向顺序(0→6);即使将循环改为正向执行,index2D的打印顺序依然是正向的。
错误原因
核心问题是闭包的执行时机和等待时长的逻辑不匹配:
- 所有节点的
SKAction是被同时添加并启动计时的,并非按遍历顺序依次执行。 - 逆向遍历时,你给索引6的节点设置了
6*2=12秒的等待,索引5是5*2=10秒,直到索引0是0秒等待。等待时间越短的节点会越早执行打印,所以最终顺序变成0→6,和遍历顺序完全相反。 - 正向遍历的话,索引0等待0秒先执行,索引1等2秒后执行,自然还是0→6的顺序。
解决方法
方法1:调整等待时长的计算逻辑
让后遍历到的小索引节点等待更长时间,保证遍历顺序和执行顺序一致:
fileprivate func fadeOutNodes2() { genericNodeWalker(.backwards) { index2D in // 用节点总数减去当前索引,让大索引节点等待时间更短 let wait = SKAction.wait(forDuration: Double(self.nodes.count - 1 - index2D) * 2) let custom = SKAction.run { print("index2D \(index2D)") } let sequence = SKAction.sequence([wait,custom]) self.nodes[index2D].run(sequence) } }
这样逆向遍历时,索引6的等待时长为0,会最先执行打印;索引5等待2秒后执行,以此类推,最终打印顺序就是6→0,和遍历顺序一致。
方法2:使用串行动作执行
如果不想依赖等待时长,可通过动作的完成回调实现严格串行执行:
fileprivate func fadeOutNodes2() { var previousAction: SKAction? = nil // 按逆向顺序遍历节点 for indexNode in stride(from: self.nodes.count - 1, through: 0, by: -1) { let printAction = SKAction.run { print("index2D \(indexNode)") } if let prevAction = previousAction { // 当前动作在之前的动作完成后执行 previousAction = SKAction.sequence([prevAction, printAction]) } else { previousAction = printAction } } // 执行最终的串行动作序列 previousAction.map { self.run($0) } }
这种方式下,所有打印动作会严格按遍历顺序(6→0)依次执行,无需依赖等待时长,执行顺序更精准可控。
内容的提问来源于stack exchange,提问作者user3069232
相关产品推荐
相关产品推荐

