ApplicationDidEnterBackground:NSTimer时出现意外崩溃

时间:2017-10-10 08:29:41

标签: swift nstimer

昨天,我问过因为我的计时器在后台遇到问题,我找到了一个解决方案让它工作但是现在,当我的应用程序进入后台时我遇到了问题。

在后台运行:

backgroundTaskIdentifier = UIApplication.shared.beginBackgroundTask(expirationHandler: {
        UIApplication.shared.endBackgroundTask(self.backgroundTaskIdentifier!)
    })

这是我的计时器:

let interval = 0.01
timer = Timer.scheduledTimer(timeInterval: interval, target: self, selector:#selector(ViewController.updateTimer), userInfo: nil, repeats: true)
RunLoop.main.add(timer, forMode: RunLoopMode.commonModes)

这是我的updateTimer函数:

func updateTimer () {
    var j = 0
    for _ in rows {
      if (rows[j]["Playing"] as! Bool == true ) {
            rows[j]["time"] = (rows[j]["time"] as! Double + interval) as AnyObject
            rows[j]["lastTime"] = (rows[j]["lastTime"] as! Double + interval) as AnyObject
      }
      if (rows[j]["lastTime"] as! Double > 60.0) {
            min[j] += 1
            rows[j]["lastTime"] = 0.00 as AnyObject
      }
      j += 1
    }
}

在我的applicationDidEnterBackground方法中,我调用了这个函数:

func backgroundTimer() {
    print("background") // This Print works fine
    timer.invalidate() // Never works
    interval = 1.00 // Crash when interval change from 0.01 to 1.00
    timer = Timer.scheduledTimer(timeInterval: interval, target: self, selector:#selector(ViewController.updateTimer), userInfo: nil, repeats: true)
}

当我的应用程序在后台输入时,这是我的输出:

enter image description here

  

双倍是间隔。

     

在Info.plist中我添加:应用程序不在后台运行:NO。

让我知道我做错了什么?

编辑:

  

viewDidLoad方法中行的初始化

let i: [String : AnyObject] = ["time": time as AnyObject, "Playing": false as AnyObject, "lastTime": 0.00 as AnyObject, "lapNumber": 0 as AnyObject, "min": 0 as AnyObject]
rows.append(i as [String : AnyObject])

3 个答案:

答案 0 :(得分:1)

您的基本问题似乎是AnyObject用于非真正对象的事情。它会导致as! Bool失败。

这是一个游乐场片段,它通过允许字典中的简单值来获取存储的Bool值。

var rows: [[String : Any]] = []
let i: [String : Any] = ["time": time, "Playing": false, "lastTime": 0.00, "lapNumber": 0, "min": 0]
rows.append(i)

let playing = rows[0]["Playing"]
if let playing = playing as? Bool {
    print("Bool")
} else {
    print("Something else \(String(describing: playing))")
}

答案 1 :(得分:1)

我找到了解决这个问题的方法。

使用NSNotification。

override func viewWillAppear(_ animated: Bool) {
  NotificationCenter.default.addObserver(self, selector:#selector(ViewController.backgroundTimer), name:NSNotification.Name.UIApplicationDidEnterBackground, object: nil)

  NotificationCenter.default.addObserver(self, selector:#selector(ViewController.backToForeground), name:NSNotification.Name.UIApplicationWillEnterForeground, object: nil)
}

func backgroundTimer(notification : NSNotification) {
    self.timer.invalidate()
    interval = 1.00
    timer = Timer.scheduledTimer(timeInterval: interval, target: self, selector:#selector(ViewController.updateTimer), userInfo: nil, repeats: true)
    RunLoop.main.add(timer, forMode: RunLoopMode.commonModes)
}

func backToForeground(notification: NSNotification) {
    self.timer.invalidate()
    interval = 0.01
    timer = Timer.scheduledTimer(timeInterval: interval, target: self, selector:#selector(ViewController.updateTimer), userInfo: nil, repeats: true)
    RunLoop.main.add(timer, forMode: RunLoopMode.commonModes)
}
  

别忘了添加backgroundTaskIdentifier。

答案 2 :(得分:1)

我想您正在使用AppDelegate mainVC方法创建主副本。这就是为什么你的计时器永远不会在你的ViewController中失效。它在您的副本中无效。 看看这个答案:Pausing timer when app is in background state Swift