I make app on page-based.based. I have multiple different controllers. Every controller has NSTimer
which turn on when the controller viewDidAppear()
. I made that NSTimer turn off when controller is viewDidDisappear()
. It works when I slowly slide between controllers but if I fast slide controller some timers don't turn off. I tried several different methods. The first method I post notification to the function which turn off timer but it also works when I slowly slide between controllers. The second method I created public class timer which I used for every controller it doesn't work for me. I don't know how can I make it. Please help me. I also have NSTimer in UIView which is located on UIViewController and I need that when UIViewController is disappear to turn off two timers. How can I make it?
My examples on ViewController
var timer: NSTimer!
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(true)
notificationCenter.postNotificationName("turnOnMemoryArc", object: nil)
timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: "showMemory", userInfo: nil, repeats: true)
}
override func viewDidDisappear(animated: Bool) {
super.viewDidDisappear(true)
if timer != nil {
timer.invalidate()
}
notificationCenter.postNotificationName("turnOffMemoryArc", object: nil)
}
This code in the view
override func drawRect(rect: CGRect) {
notificationCenter.addObserver(self, selector: "turnOnMemoryTimer", name: "turnOnMemoryArc", object: nil)
notificationCenter.addObserver(self, selector: "turnOffMemoryTimer", name: "turnOffMemoryArc", object: nil)
// timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: "drawMemoryArc", userInfo: nil, repeats: true)
}
func turnOnMemoryTimer() {
print("memory timer is on")
timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: "drawMemoryArc", userInfo: nil, repeats: true)
}
func turnOffMemoryTimer() {
if timer != nil {
timer.invalidate()
}
print("Memory timer turned")
}
The second method
import Foundation
public class GlobalTimer {
public init() { }
public var controllerTimer: NSTimer!
public var viewTimer: NSTimer!
}
ViewController
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(true)
notificationCenter.postNotificationName("turnOnBatteryArc", object: nil)
if GlobalTimer().controllerTimer != nil {
GlobalTimer().controllerTimer.invalidate()
GlobalTimer().controllerTimer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: "batteryStateForLabel", userInfo: nil, repeats: true)
} else {
GlobalTimer().controllerTimer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: "batteryStateForLabel", userInfo: nil, repeats: true)
}
}
UIView
func turnOnBatteryTimer() {
print("turnOnBatteryTimer arc")
if GlobalTimer().viewTimer != nil {
GlobalTimer().viewTimer.invalidate()
GlobalTimer().viewTimer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: "drawBatteryArc", userInfo: nil, repeats: true)
} else {
GlobalTimer().viewTimer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: "drawBatteryArc", userInfo: nil, repeats: true)
}
}
The main problem in your code is GlobalTimer()
. This creates new GlobalTimer
instance every single time you do write GlobalTimer()
.
Four different instance in the following piece of code - no shared state.
if GlobalTimer().viewTimer != nil {
GlobalTimer().viewTimer.invalidate()
GlobalTimer().viewTimer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: "drawBatteryArc", userInfo: nil, repeats: true)
} else {
GlobalTimer().viewTimer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: "drawBatteryArc", userInfo: nil, repeats: true)
}
You can fix it with singleton pattern ...
public class GlobalTimer {
public static let sharedInstance = GlobalTimer()
private init() { }
public var controllerTimer: NSTimer!
public var viewTimer: NSTimer!
}
... by replacing all GlobalTimer()
occurences ...
if GlobalTimer().viewTimer != nil {
... with GlobalTimer.sharedInstace
...
if GlobalTimer.sharedInstance.viewTimer != nil {
Next step is !
removal, which is dangerous and can lead to crash if you don't know what you're doing.
public class GlobalTimer {
public static let sharedInstance = GlobalTimer()
private init() { } <-- avoid instantiation outside the file
public var controllerTimer: NSTimer? <-- was !
public var viewTimer: NSTimer? <-- was !
}
Remaining step is to replace your code using GlobalTimer
...
if GlobalTimer().viewTimer != nil {
GlobalTimer().viewTimer.invalidate()
GlobalTimer().viewTimer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: "drawBatteryArc", userInfo: nil, repeats: true)
} else {
GlobalTimer().viewTimer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: "drawBatteryArc", userInfo: nil, repeats: true)
}
... with ...
GlobalTimer.sharedInstance.viewTimer?.invalidate()
GlobalTimer.sharedInstance.viewTimer = NSTimer.scheduled...
First line says - call invalidate()
function on viewTimer
if viewTimer != nil
otherwise nothing happens (similar to nil
messaging in ObjC, ...). This allows you to remove the if
condition, because it invalidates timer or does nothing.
Second line just assigns new timer.