代码之家  ›  专栏  ›  技术社区  ›  NiteIsAFK

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

  •  1
  • NiteIsAFK  · 技术社区  · 7 年前

    现在,我正在开发一个简单的点击游戏。我想能够运行一个自动点击器,自动添加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 回复  |  直到 7 年前
        1
  •  2
  •   Xcoder    7 年前

    喜欢我的答案 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
        }
    }
    

    这使用 Timer 在Swift中。

    P、 虽然这与问题不太相关,但您应该考虑在camel-case而不是snake-case中重命名变量和函数。

        2
  •  0
  •   Rob Md Fahim Faez Abir    7 年前

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

    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. 当您使用 目标 / 选择器 方法中,一个运行的计时器保持对 目标 这意味着如果关闭视图控制器,计时器将继续运行,视图控制器将不会释放。将计时器的基于闭包的格式副本与 [weak self] 模式确保计时器不会保留对视图控制器的强引用。

    3. 由于计时器不再保持对视图控制器的强引用,我们现在可以使用 deinit 确保如果关闭视图控制器,计时器也将停止。

        3
  •  0
  •   Dan Karbayev    7 年前

    还有一个选项:

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