swiftloopsclosuresskaction

Swift loop runs in reverse? Code conundrum


I don't understand what is happening in this code...

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)
    }
}

I ask it to count backwards, which it does; but the code fadeOutNodes2 within the encapsulatedMethod runs forwards?

indexNode 6
indexNode 5
indexNode 4
indexNode 3
indexNode 2
indexNode 1
indexNode 0
index2D 0
index2D 1
index2D 2
index2D 3
index2D 4
index2D 5
index2D 6

Is there an obvious mistake here I cannot and I cannot see the wood for the trees? If I change the loop to run forwards, it also runs forwards.

How can I make it run backwards?


Solution

  • I'm not quite sure what you are trying to do, but a better API for your genericNodeWalker might be something like this (I'm assuming nodes is an array of SKNode, change the type if required):

    fileprivate func genericNodeWalker(_ direction:Follow, encapsulatedMethod: (_ index: Int, _ node: SKNode) -> Void) {
        switch direction {
        case .forwards:
            nodes.enumerated().forEach(encapsulatedMethod)
        case .backwards:
            nodes.reversed().enumerated().forEach(encapsulatedMethod)
        }
    }
    
    
    fileprivate func fadeOutNodes2() {
        genericNodeWalker(.backwards) { index, node  in
            let wait = SKAction.wait(forDuration: Double(index) * 2)
            let custom = SKAction.run {
                print("index \(index)")
            }
            let sequence = SKAction.sequence([wait,custom])
            node.run(sequence)
        }
    }
    

    The walker will just call the callback with the nodes in the order you ask for, and will always pass a zero-based increasing index with each call.

    So, if you have nodes a through c then the walker will call encapsulatedMethod with (0,a), (1,b), (2,c) when interating forwards, and will call it with (0,c), (1,b), (2,a) when iterating backwards. The walker doesn't care what you do with the indexes. It doesn't care about delays. It just delivers the nodes to the callback method in the order you ask for and provides an index for each node that starts at 0.

    This also means that the callback function itself is passed a node and doesn't need to find it in self.nodes based on an index. There's also no need to use @escaping as the callback closure does not escape. It will be called for each node before genericNodeWalker returns.

    Maybe this is better, maybe not. But I think it is a cleaner API.