简体   繁体   中英

How can I create delay inside while loop in Swift 2?

I would need help with this while loop - what I'm trying to do is slow down the whole process of removing and adding new circles while radius is changing every time this happens. I'm becoming really desperate, I've tried using both dispatch_after and sleep inside the loop (which I found online) but neither of them is suitable, they basically stop the whole app. If I put them in the while loop, nothing happens. Thanks in advance!

while radius < 100 {

    self.removeAllChildren()
    addCircle()
    radius++
    print(radius)            
}

Basically you just need to do few simple things:

Here is the example of how you can do it. The important part is action sequence. You create the step above, and repeat it forever. Each time you check radius value and based on that you stop the action (remove it by the key). And that's it. You can change spawning speed by changing action's duration parameter.

Using NSTimer might seem like an easier solution, but NSTimer doesn't respect node's (or scene's or view's) paused state. So, imagine this situation:

  • You start spawning of nodes
  • User receive phone call and app automatically goes to background

Because NSTimer is not automatically paused, the nodes will continue with spawning. So you have to take an additional step and invalidate/restart timer by your self. When using SKAction, this is done automatically. There are some other flaws of using NSTimer in SpriteKit, search SO about all that, there are some posts which covering all this.

import SpriteKit

class GameScene: SKScene{

    var radius:UInt32 = 0

    override func didMoveToView(view: SKView) {

        startSpawning()
    }

    func startSpawning(){

        let wait = SKAction.waitForDuration(0.5)

       // let wait = SKAction.waitForDuration(1, withRange: 0.4) // randomize wait duration

        let addNode = SKAction.runBlock({

            [unowned self] in //http://stackoverflow.com/a/24320474/3402095 - read about strong reference cycles here

            if(self.radius >= 30){ 

                if self.actionForKey("spawning") != nil {

                    self.removeActionForKey("spawning")
                }
            }

            self.radius++
            let sprite = self.spawnNode()
            sprite.position = CGPoint(x: Int(arc4random()) % 300,  y: Int(arc4random()) % 300) // change this to randomize sprite's position to suit your needs

            self.addChild(sprite)
        })
        //wait & add node   
        let sequence = SKAction.sequence([wait, addNode])
        //repeat forever
        runAction(SKAction.repeatActionForever(sequence), withKey: "spawning")

    }

    func spawnNode()->SKSpriteNode{
        let sprite = SKSpriteNode(color: SKColor.purpleColor(), size: CGSize(width: 50, height: 50))
        //Do sprite initialization here
        return sprite
    }
}

The sleep stops the whole app because you are running the loop on the main thread.

You can solve this problem in one of two ways...

1) Use an NSTimer. Set it to the amount of time you want to delay. Put the body of the loop in the timer's trigger function and disable the timer when it has been called enough times. This is the best solution.

2) Wrap the loop in a dispatch async block to a background thread and put a sleep in the loop. If you do this though, you will have to wrap the UI code in another dispatch async block that comes back to the main thread.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM