2017-10-10 144 views
1

昨天,我问,因为我的计时器在后台有问题,我找到了一个解决方案,使其工作,但现在,当我的应用程序进入后台时遇到问题。在后台ApplicationDidEnterBackground发生意外的崩溃: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

的是双间隔。

In 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]) 
+0

rows [j] [“Playing”]的值显然为零。 –

+0

@AmeyaVichare感谢您的回答。它不能为零,它不是前景零,我不明白为什么它可以在后台 – pierreafranck

+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))") 
} 
+0

感谢您的回答。我测试过这种方式,但同样的结果时,appDidEnterBackground:'( – pierreafranck

+0

如果您使用Phillip片段,然后你崩溃,因为解包零值应该消失...所以你应该有不同的崩溃现在... –

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。

1

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

+0

谢谢。这个答案解决我的问题!看看我的回答:) – pierreafranck