【问题标题】:Implementing NSTimer into Code - Swift在代码中实现 NSTimer - Swift
【发布时间】:2015-03-30 02:45:38
【问题描述】:

我在代码中使用/实现 NSTimer 时遇到了一些麻烦。到目前为止,我有这个:

//Delay function from http://stackoverflow.com/questions/24034544/dispatch-after-gcd-in-swift/24318861#24318861
func delay(delay:Double, closure:()->()) {
    dispatch_after(
        //adds block for execution at a specific time
        dispatch_time(
            //creates a dispatch time relative to default clock
            DISPATCH_TIME_NOW,
            //Indicates that something needs to happen imediately
            Int64(delay * Double(NSEC_PER_SEC))
            //a 64bit decleration that holds the delay time times by the amount of nanoseconds in one seconds, inorder to turn the 'delay' input into seconds format
        ),
        dispatch_get_main_queue(), closure)
}


@IBAction func computerTurn(){

    if(isFirstLevel){levelLabel.text = ("Level 1"); isFirstLevel = false}
    else{ level++ }

    var gameOrderCopy = gameOrder
    var randomNumber = Int(arc4random_uniform(4))
    gameOrder.append(randomNumber)
    var i = 0
    var delayTime = Double(1)

    println(Double(NSEC_PER_SEC))
    for number in self.gameOrder{


        if number == 0{
            delay(delayTime++){self.greenButton.highlighted = true}
            self.delay(delayTime++){
                self.greenButton.highlighted = false
            }
        }

        else if number == 1{
            delay(delayTime++){self.redButton.highlighted = true}
             self.delay(delayTime++){
                self.redButton.highlighted = false
            }

        }

        else if number == 2{
            delay(delayTime++){self.yellowButton.highlighted = true}
             self.delay(delayTime++){
                self.yellowButton.highlighted = false
            }
        }
        else if number == 3{
            delay(delayTime++){self.blueButton.highlighted = true}
             self.delay(delayTime++){
                self.blueButton.highlighted = false
            }
        }
        println(delayTime)


    }
}

我需要做的是替换定时器功能,或者去掉它,和这里发生的事情一样,但是使用 NSTimer。

谢谢

【问题讨论】:

  • 为什么? dispatch_after() 是解决此问题的更好工具。 NSTimer 会不必要地复杂。
  • @RobNapier,一旦 delayTime 变量超过 13,dispatch_after() 就会出现故障,因为延迟时间太长了,所以我需要使用 NSTimer 所以它可以超过 13 秒。
  • @RobNapier 在 iOS 8(但不是 iOS 7)中,如果你安排一堆 dispatch_after,就像上面的代码一样,(比如说,20 个,每个间隔 1 秒),前几个很好,但你会看到它开始将后面的一些合并成组。您必须使用重复计时器。如果你想使用dispatch_after,你不能像这段代码那样预先安排它们,而是只安排第一个并让完成块触发下一个。
  • @JohnnyCash 同样,请告诉我们您是在 iOS 还是 Mac OS X 上执行此操作。

标签: swift nstimer


【解决方案1】:

NSTimer 在这种情况下可能有点笨拙,因为它需要使用 target-action 或 NSInvocation。但是,NSTimerCFRunLoopTimer 是免费桥接的,您可以使用块调用:

func delay(delay:Double, closure:()->()) {
    let fireDate = delay + CFAbsoluteTimeGetCurrent()
    let timer = CFRunLoopTimerCreateWithHandler(kCFAllocatorDefault, fireDate, 0, 0, 0) { _ in
        closure()
    }
    CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopCommonModes)
}

【讨论】:

  • 我会假设这会表现出与dispatch_after 相同的合并行为,但事实并非如此。很棒。
  • 这种合并行为是 GCD 的一部分,并且发生在自定义事件中(即任何通过 dispatch_async 的事件)。 CFRunLoop/NSTimer 早于 GCD(很多),所以他们没有这种行为。顺便说一句,如果您想为此使用 GCD,您可以使用 dispatch_source_createdispatch_source_set_timer 创建一个计时器而不是自定义事件。
  • 是的。如果您使用调度计时器并希望确保不会发生合并(尤其是在 Mac OS X 上使用 App Nap),您可以指定 DISPATCH_TIMER_STRICT 作为 dispatch_source_set_timer 的第三个参数。 (我知道你可能知道 Nate,但我会为未来的读者提到这一点。)
  • @JohnnyCash:第一行获取当前时间 + 延迟,因为 CFRunLoopTimer 需要实际执行时间,而不是像 NSTimer 这样的偏移量。最后两行基本上加起来就是调用NSTimer.scheduledTimerWithTimeInterval(...),但使用闭包而不是目标和选择器或调用。这两个函数的 CFRunLoopTimer docs 应该解释其余部分。
【解决方案2】:

我建议:

  • 设置一些类属性来维护“当前”数字索引(从 0 开始);

  • 启动您的重复计时器;

  • 计时器的处理程序将使用索引来确定要更改的按钮,然后执行一次“打开高亮显示”,然后执行dispatch_after 以“关闭高亮显示”;

    然后,此处理程序将查看索引并确定您是否位于列表的末尾。如果你是,那么取消计时器,你就完成了。如果您不在列表的末尾,则增加“当前索引”并等待下一个计划的计时器触发。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-18
    • 2014-08-13
    • 1970-01-01
    • 1970-01-01
    • 2021-08-06
    • 2015-03-15
    相关资源
    最近更新 更多