2017-10-10 147 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