简体   繁体   English

为什么计时器在timer.invalidate()之后继续运行?

[英]Why does my timer keep running after timer.invalidate()?

Making a Yatzee game. 制作Yatzee游戏。 I've got 5 images and a button on the screen: 我有5张图片和一个按钮在屏幕上:

@IBOutlet var button: UIButton!
@IBOutlet var dice1: UIImageView!
@IBOutlet var dice2: UIImageView!
@IBOutlet var dice3: UIImageView!
@IBOutlet var dice4: UIImageView!
@IBOutlet var dice5: UIImageView!

The images in my assets folder are named Dice1.png, Dice2.png all the way to Dice6.png. 我的资源文件夹中的图像一直命名为Dice1.png,Dice2.png一直到Dice6.png。

When the button is tapped, Int.random picks one of the six images to display. 轻按按钮时,Int.random会选择要显示的六个图像之一。

@IBAction func button(_ sender: Any) {
    dice1.image = UIImage(named: "Dice\(Int.random(in: 1...6))")
    dice2.image = UIImage(named: "Dice\(Int.random(in: 1...6))")
    dice3.image = UIImage(named: "Dice\(Int.random(in: 1...6))")
    dice4.image = UIImage(named: "Dice\(Int.random(in: 1...6))")
    dice5.image = UIImage(named: "Dice\(Int.random(in: 1...6))")
}

Works perfect! 完美的作品!

Here's my problem: 这是我的问题:

I'd like the dice to cycle through the images rapidly after the first tap (as if the dice are being shaken in a cup), and then when the button is tapped again they should stop cycling (as if they were rolled). 我希望骰子在第一次点击后迅速在图像中循环(就像骰子在杯子中摇晃一样),然后当再次轻按按钮时,它们应该停止循环(就像它们被滚动一样)。

I was thinking to do this by using a timer. 我当时想通过使用计时器来做到这一点。 When the button is pressed, the timer fires every 0.1 second, displaying a different image every 0.1 second. 按下按钮时,计时器每0.1秒触发一次,每0.1秒显示一次不同的图像。

var timer = Timer()
var state = 0

@IBAction func button(_ sender: Any) {
    if state == 0 {
        Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(roll), userInfo: nil, repeats: true)
        button.setTitle("Roll", for: UIControl.State.normal)
        state = 1
    } else {
        timer.invalidate()
        button.setTitle("Shake", for: UIControl.State.normal)
        state = 0
    }
}

@objc func roll() {
    dice1.image = UIImage(named: "Dice\(Int.random(in: 1...6))")
    dice2.image = UIImage(named: "Dice\(Int.random(in: 1...6))")
    dice3.image = UIImage(named: "Dice\(Int.random(in: 1...6))")
    dice4.image = UIImage(named: "Dice\(Int.random(in: 1...6))")
    dice5.image = UIImage(named: "Dice\(Int.random(in: 1...6))")
}

After the button is pressed the first time, the dice are all changing every 0.1 seconds and it looks cool, and the button title changes to "Roll". 第一次按下按钮后,骰子每隔0.1秒都会改变一次,看上去很酷,并且按钮标题变为“滚动”。

When the button is pressed the second time, the button title changes back to "Shake" as is expected, but rather than stopping, the dice start changing images twice as fast, which I think means the timer is being called again, rather than timer.invalidate() 当第二次按下按钮时,按钮标题将按预期方式变回“摇动”状态,但是骰子并没有停止,而是以两倍快的速度开始更改图像,这意味着计时器被再次调用,而不是计时器.invalidate()

I'm stumped because each time I press the button, the title changes as expected, meaning that the variable "state" is correctly switching back and forth between 0 and 1. However, timer.invalidate() apparently isn't the way to get the dice to stop rolling. 我很沮丧,因为每次按下按钮时,标题都会按预期更改,这意味着变量“状态”正确地在0和1之间来回切换。但是,使用timer.invalidate()显然不是让骰子停止滚动。

What's a better way to do this? 有什么更好的方法?

Thanks in advance for any help! 在此先感谢您的帮助!

Timer.scheduledTimer(timeInterval...)

creates a timer and runs it. 创建一个计时器并运行它。 The function also returns the timer that is created, but it is not stored anywhere, so you cannot invalidate it. 该函数还返回创建的计时器,但是它没有存储在任何地方,因此您不能使其无效。

Your first line 您的第一行

var timer = Timer()

is strange. 很奇怪 You declare a variable, and assign a Timer object that has been created without any parameters. 您声明一个变量,并分配一个不带任何参数创建的Timer对象。 That object is totally useless. 该对象完全没有用。 You later call 你以后打电话

timer.invalidate()

which invalidates this timer, which is pointless because it wasn't used anywhere anyway. 这会使该计时器无效,这是没有意义的,因为无论如何它都没有在任何地方使用。

I suppose you started writing code until it compiled without errors. 我想您开始编写代码,直到代码编译正确为止。 Here's what you should have done: 这是您应该做的:

// Create an optional Timer variable, initially nil
var timer: Timer?

// Later: Store a scheduled timer
timer = Timer.scheduledTimer(timeInterval...)

// Invalidate if the timer exists and set to nil
timer?.invalidate()
timer = nil

You can also get rid of the "state" variable and just test the timer variable instead of state == 0 您也可以摆脱“状态”变量,只测试计时器变量而不是状态== 0

if timer == nil {
} else {
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM