【问题标题】:App crashes after the timer Instead of re-enabling button计时器后应用程序崩溃而不是重新启用按钮
【发布时间】:2018-09-21 16:47:03
【问题描述】:

我是 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 )

【问题讨论】:

  • 欢迎来到 Stackoverflow!请包括您得到的错误或输出或行为。
  • 线程 1:信号 SIGABRT

标签: swift xcode uibutton nstimer


【解决方案1】:

欢迎来到 Stack Overflow。让我带您了解一下您的代码在按下按钮后正在做什么。

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

}

【讨论】:

    【解决方案2】:

    这里有几个问题:

    导致崩溃的原因是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

    我建议尝试根据我提供给您的信息找到解决方案。如果您有任何问题,请告诉我,欢迎堆栈溢出!

    【讨论】:

    • 我认为这个东西崩溃的最重要原因是计时器正在调用一个选择器 MarketButton:它需要一个按钮作为它的第一个也是唯一的参数。您的任何其他评论仍然适用,但它应该会失败,因为计时器不是 UIButton 类型,这就是它无法检查该对象的 isEnabled 属性的原因。
    • 嗯,您想发布解决方案吗?需要多个答案:O
    • 我认为您可以将我的评论添加到您的答案中。否则,我只会重新发布您的大部分原始答案;-)
    • 谢谢你们,@boidkan 感谢你们的帮助和问候,不幸的是,我的代码仍然有一点问题。计时器似乎不起作用,按钮也没有禁用。跨度>
    • var timer: 定时器?一个 IBOutlet 弱 var marketButtons: UIButton! A IBAction func marketButton(_ sender: UIButton) { marketLabel.text = Int(arc4random_uniform(10)).description timer = Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(enableButton), userInfo: nil,重复:false) } 一个 objc func enableButton() { timer = nil marketButtons.isEnabled = !(timer?.isValid ?? false)
    猜你喜欢
    • 2015-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多