计时器后应用崩溃,而不是重新启用按钮

时间:2018-09-21 16:47:03

标签: swift xcode uibutton nstimer

我是XCode的新手,所以将不胜感激。

按下按钮时,应禁用该按钮,并应显示一个随机数并触发计时器。完成计时器后,将再次启用该按钮。

这是按钮代码:

@IBAction func MarketButton(_ sender: UIButton) {
    let t = Int(arc4random_uniform(10))
    MarketLabel.text = String (t)
    let timer = Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(MarketViewController.MarketButton), userInfo: nil, repeats: false)
    sender.isEnabled = !(timer.isValid )

2 个答案:

答案 0 :(得分:1)

欢迎堆栈溢出。让我向您介绍在按下按钮后此刻您的代码正在做什么。

  1. 创建一个介于0到10之间的随机数
  2. 将数字放入标签
  3. 安排计时器以启动相同的功能
  4. 如果计时器有效,它将禁用该按钮。如果计时器无效,它将启用该按钮。

但是,在计时器触发后,它将调用相同的函数。这次,它将没有相同的参数。在第一次运行中,按钮将自身传递给第一个参数。这次,计时器将是第一个参数。不幸的是,由于选择器API类型不安全,因此会发生这种情况。因此,一旦触发计时器,就会发生以下情况:

  1. 该函数被调用
  2. 生成随机数并将其写入标签
  3. 新计时器启动
  4. 正在运行您的iOS应用的目标C运行时,尝试查找和isEnabled属性,该属性在您的计时器上找不到,并且会崩溃。

因此,对于计时器来说,至关重要的是调用另一个建议的功能,例如@boidkan。我建议像这样:

class TimebombViewController {
    @IBOutlet weak var timerLabel: UILabel!
    @IBOutlet weak var startButton: UIButton!

    var timer: Timer?
    @IBAction startButtonPressed(_ sender:UIButton){
        timerLabel.text = Int(arc4random_uniform(10)).description
        timer = Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(timerFired), userInfo: nil, repeats: false)
        refreshButtonState()
    }

    @objc timerFired(_ timer:Timer){
        timer = nil
        refreshButtonState()
    }

    func refreshButtonState(){
        startButton.isEnabled = !(timer?.isValid ?? false)
    }

}

答案 1 :(得分:0)

您在这里遇到一些问题:

导致崩溃的原因是MarketButton要求您将UIButton作为参数传递,而在触发时计时器不会执行该参数。您可以通过在按钮scheduledTimer的userInfo参数中传递来完成此操作。这是有关如何进行that的堆栈溢出文章。

但是,即使执行此操作,仍然无法正常工作。 您需要创建一种方法来处理计时器完成时间。

类似的东西:

func enableButton() {
    yourButton.isEnabled = true
}

然后将其用作选择器,而不是MarketButton方法。

像这样:

let timer = Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(enableButton), userInfo: nil, repeats: false)

通过将“ MarketButton”用作计时器的选择器,将导致无限循环。计时器完成后,它会调用方法,然后触发另一个计时器,依此类推。

这两个代码行是另一个问题:

let timer = Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(MarketViewController.MarketButton), userInfo: nil, repeats: false)
sender.isEnabled = !(timer.isValid )

在这种情况下,计时器几乎总是有效的,因为您只需对其进行设置。因此!(timer.isValid)基本上总是返回false。但是,如果您遵循我的建议并触发其他方法而不是MarketButton,那么这将不是问题。

另外请注意,在命名函数时,请勿使用大写字母,因此MarketButton应该为marketButton

我建议尝试使用我提供的信息找到解决方案。如果您有任何问题,请通知我,并欢迎堆栈溢出!