So I am building an simple iOS app using Swift. I need to kill my NSTimer
after the app entering background, and create a new one after the app is active again.
Initially my solution is to create a timer of NSTimer
class in ViewDidLoad()
in the main controller file. And this causes a bug in my app.
I guess I need to kill the timer by using applicationDidEnterBackground()
in AppDelegate.swift. But I am not exactly sure about how to do it. Should I create the timer class in AppDelegate.swift or in the main controller? I don't know how Swift files share classes.
I have searched online for solutions, but those posts are all too old, the solutions are written in Objective-C.
I am an absolutely beginner. So I hope someone can explain it in Swift.
Here is the code in my main controller TodoTableViewController.swift:
import UIKit
import CoreData
class TodoTableViewController: UITableViewController, NSFetchedResultsControllerDelegate {....
...
...
override func viewDidLoad() {
super.viewDidLoad()
var fetchRequest = NSFetchRequest(entityName: "Todo")
let sortDescriptor = NSSortDescriptor(key: "dayleft", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
if let managedObjectContext = (UIApplication.sharedApplication().delegate as AppDelegate).managedObjectContext {
fetchResultController = NSFetchedResultsController(fetchRequest:fetchRequest, managedObjectContext: managedObjectContext, sectionNameKeyPath: nil, cacheName: nil)
fetchResultController.delegate = self
var e: NSError?
var result = fetchResultController.performFetch(&e)
todos = fetchResultController.fetchedObjects as [Todo]
if result != true {
println(e?.localizedDescription)
} }
var timer = NSTimer.scheduledTimerWithTimeInterval(10, target: self, selector:"update", userInfo:nil, repeats: true)
}
...
}
If I am going to invalidate the timer in AppDelegate.swift, how can I refer the timer to the one I created in TodoTableViewController.swift? Or maybe I should put all the code related to timer in AppDelegate.swift?
update
I have tried to use NSNotificationCenter, here is my code.
import UIKit
import CoreData
class TodoTableViewController: UITableViewController, NSFetchedResultsControllerDelegate {
...
var timer = NSTimer.scheduledTimerWithTimeInterval(10, target: self, selector:"viewDidLoad", userInfo:nil, repeats: true)
func update(){
.....
}
override func viewDidLoad() {
super.viewDidLoad()
...
let notificationCenter = NSNotificationCenter.defaultCenter()
notificationCenter.addObserver(self, selector: "didEnterBackground", name: "UIApplicationDidEnterBackgroundNotification", object: UIApplication.sharedApplication())
notificationCenter.addObserver(self, selector: "didBecomeActive", name: "UIApplicationWillEnterForegroundNotification", object: UIApplication.sharedApplication())
}
func didEnterBackground() {
timer.invalidate()
}
func didBecomeActive() {
var timer = NSTimer.scheduledTimerWithTimeInterval(10, target: self, selector:"update", userInfo:nil, repeats: true)
}
...
}
Since timer is declared in didBecomeActive()
, in didEnterBackground()
there is an error: does not have a member named "timer". If I declare timer
outside didBecomeActive()
like the code I posted above, there is an error saying "Extra argument 'selector' in call". I already parse the function update()
to the selector. I don't know where this error comes from.
Updated your code and added few comments:
class TodoTableViewController: UITableViewController, NSFetchedResultsControllerDelegate
//better to instantiate timer inside viewDidLoad
var timer: NSTimer!
func update(){ }
override func viewDidLoad() {
super.viewDidLoad()
startTimer()
let notificationCenter = NSNotificationCenter.defaultCenter()
//UIApplicationDidEnterBackgroundNotification & UIApplicationWillEnterForegroundNotification shouldn't be quoted
notificationCenter.addObserver(self, selector: "didEnterBackground", name: UIApplicationDidEnterBackgroundNotification, object: nil)
notificationCenter.addObserver(self, selector: "didBecomeActive", name: UIApplicationWillEnterForegroundNotification, object: nil)
}
func didEnterBackground() {
self.timer.invalidate()
}
func didBecomeActive() {
startTimer()
}
func startTimer() {
self.timer = NSTimer.scheduledTimerWithTimeInterval(10, target: self, selector:"update", userInfo:nil, repeats: true)
}
}
Also notice that NSTimer
strongly keeps it's target
. So when closing viewcontroller - timer should be invalidated explicitely. Or memory leak will occur and TodoTableViewController
will never be destroyed.