截至目前,我正致力于开发一款简单的点击游戏。我希望能够运行一个自动点击器,自动将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
}
}
}
答案 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
}
}
}
}
但关键点是:
定时器的基于块的再现使您摆脱了令人困惑的target
/ selector
语法。
当您使用target
/ selector
方法时,正在运行的计时器会保留对target
的强引用,这意味着如果您关闭视图控制器,计时器将继续运行并且视图控制器不会被释放。使用基于闭包的计时器再现与[weak self]
模式相结合可确保计时器不会对视图控制器保持强引用。
由于计时器不再保留对视图控制器的强引用,我们现在可以使用deinit
来确保如果取消视图控制器,那么计时器也将停止。 / p>