延迟某个功能而不停止整个程序// Swift 4

时间:2018-03-05 23:32:55

标签: ios swift multithreading delay

截至目前,我正致力于开发一款简单的点击游戏。我希望能够运行一个自动点击器,自动将X点击添加到您的总数中,每次之间延迟1秒。我的问题是,如果我试图延迟和/或不运行自动点击器,它将冻结整个程序。我已经阅读了关于线程如何工作的内容,但我还没有完全理解如何在Swift 4中完成它。

这是我到目前为止所拥有的

@IBAction func auto_clicker_add(_ sender: Any)
{
    while auto_clicker_switch.isOn == true
    {
        DispatchQueue.main.asyncAfter(deadline: .now() + 1)
        {
            self.count_taps = self.count_taps + 1
        }
    }
}

3 个答案:

答案 0 :(得分:2)

就像我对this question的回答一样,这是替代DispatchQueue的替代解决方案:

var timer: Timer?

@IBAction func auto_clicker_add(_ sender: Any) {
    timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(self.updateTimer), userInfo: nil, repeats: true)
}

@objc func updateTimer() {
    if (auto_clicker_switch.isOn == true) {
        self.count_taps += 1
    } else {
        timer.invalidate()
        timer = nil
    }
}

这在Swift中使用Timer

P.S。虽然它与问题关系不大,但您应该考虑在驼峰情况下重命名变量和函数,而不是蛇案例。

答案 1 :(得分:0)

还有一个选择:

// a little bit more meaningful name
var autoClickTimer: Timer?

@IBAction func auto_clicker_add(_ sender: Any) {
  if auto_clicker_switch.isOn {
    // make sure that timer wasn't set yet
    guard self.autoClickTimer == nil else { return }
    self.autoClickTimer = setInterval(1) { [unowned self] in
      self.count_taps += 1
    }
  } else {
    self.autoClickTimer?.invalidate()
    self.autoClickTimer = nil
  }
}

// helper function (credits: http://peatiscoding.me/uncategorized/javascript-settimeout-swift-3-0/)
func setInterval(_ interval: TimeInterval, execute: @escaping () -> Void) -> Timer {
  return Timer.scheduledTimer(timeInterval: interval, target: BlockOperation(block: execute), selector: #selector(Operation.main), userInfo: nil, repeats: true)
}

答案 2 :(得分:0)

我建议稍加注意避免强烈引用视图控制器。

class ViewController: UIViewController {

    var tapCount = 0

    // I'd suggest weak reference to timer so that when it's invalidated, this is automatically set to `nil`

    weak var timer: Timer?

    // if view controller is dismissed, stop the timer (if it hasn't already been stopped)

    deinit {
        timer?.invalidate()
    }

    // switch to turn timer on or off has changed

    @IBAction func toggleTimer(_ sender: UISwitch) {
        timer?.invalidate()

        if sender.isOn {
            timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] _ in
                self?.tapCount += 1
            }
        }
    }
}

但关键点是:

  1. 定时器的基于块的再现使您摆脱了令人困惑的target / selector语法。

  2. 当您使用target / selector方法时,正在运行的计时器会保留对target的强引用,这意味着如果您关闭视图控制器,计时器将继续运行并且视图控制器不会被释放。使用基于闭包的计时器再现与[weak self]模式相结合可确保计时器不会对视图控制器保持强引用。

  3. 由于计时器不再保留对视图控制器的强引用,我们现在可以使用deinit来确保如果取消视图控制器,那么计时器也将停止。 / p>