【问题标题】:How can I create delay inside while loop in Swift 2?如何在 Swift 2 的 while 循环中创建延迟?
【发布时间】:2015-12-09 11:21:43
【问题描述】:

我需要有关此 while 循环的帮助 - 我正在尝试做的是减慢删除和添加新圆的整个过程,而每次发生这种情况时,半径都会发生变化。我变得非常绝望,我尝试在循环中同时使用 dispatch_after 和 sleep (我在网上找到),但它们都不合适,它们基本上会停止整个应用程序。如果我将它们放在 while 循环中,则不会发生任何事情。提前致谢!

while radius < 100 {

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

【问题讨论】:

  • [NSThread sleepForTimeInterval:number of seconds you want to wait before next iteration]; 在循环内就可以了。这是在目标 C 中。寻找它的 Swift 等价物。
  • 这里是它的Apple Documentation。它将使正在运行的任何线程进入睡眠状态。如果我是你,我会将循环分派到另一个线程并在那里调用它,让该线程进入睡眠状态,同时享受完整的工作主线程。
  • 但是如果循环被分派到另一个线程从而使该线程而不是主线程进入睡眠状态,它不会工作吗? (由于我没有在 GCD 和线程方面做太多工作,我不确定,如果这是一个幼稚的问题,我很抱歉)@DanielT。
  • @DanielT。 This Code 为我工作。我可以在我的应用程序上工作,而循环一直在后台运行,每次迭代都有延迟
  • OP 显然使用了 SpriteKit ... 那么为什么不使用 SKAction 序列(它将等待并添加节点)。在这种情况下完全没有必要使用 GCD。此外 NSTimer 或 dispatch_... 方法不尊重场景(或节点)的暂停状态,并且 SKAction 或 update: 方法及其传递的 currentTime 参数是 SpriteKit 中与时间相关的操作的首选方式。

标签: swift sprite-kit


【解决方案1】:

基本上你只需要做一些简单的事情:

这里是你如何做到这一点的例子。重要的部分是动作顺序。您创建上面的步骤,并永远重复它。每次您检查半径值并根据该值停止操作(通过键将其删除)。就是这样。您可以通过更改动作的持续时间参数来更改生成速度。

使用 NSTimer 似乎是一种更简单的解决方案,但 NSTimer 不尊重节点(或场景或视图)的暂停状态。所以,想象一下这种情况:

  • 您开始生成节点
  • 用户接听电话,应用自动进入后台

由于 NSTimer 不会自动暂停,节点将继续生成。因此,您必须采取额外的步骤并自行使计时器无效/重新启动。使用 SKAction 时,这是自动完成的。在 SpriteKit 中使用 NSTimer 还有一些其他的缺陷,搜索一下,有一些帖子涵盖了所有这些。

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

【讨论】:

  • 非常感谢您的建议!
【解决方案2】:

睡眠会停止整个应用程序,因为您正在主线程上运行循环。

您可以通过以下两种方式之一解决此问题...

1) 使用 NSTimer。将其设置为您想要延迟的时间量。将循环体放在定时器的触发函数中,并在定时器被调用足够多时禁用定时器。这是最好的解决方案。

2) 在调度异步块中将循环包装到后台线程并在循环中放置睡眠。但是,如果这样做,则必须将 UI 代码包装在另一个返回主线程的调度异步块中。

【讨论】:

  • 请查看SKAction。这就是我们将在 SpriteKit 中使用的。 SKAction 与 SpriteKit 使用的更新循环配合得很好,而 GCD 和 NSTimer 则不行。您可以这样做是对的,但这绝对不是 SpriteKit 的最佳做法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-15
  • 2013-01-24
  • 2020-02-22
  • 2018-04-05
  • 2012-04-20
相关资源
最近更新 更多