Explanation
I am making a Swift 3 game using SpriteKit where I create several timers using the addTimer function I wrote below. The basic idea is that I spawn monsters using addTimer, and then despawn them using addTimer as well. Also, i'm using addTimer to do other things like keep track of player spell effects like regeneration, etc. Everytime I create a timer, I just add it to a dictionary by a unique key, this way I can reference it later in closure to remove the timer from the dictionary.
I feel like when I pause my game (by pressing an icon on my gamescene, and invoking the pauseTimers() code below) that the game doesn't really pause; it seems like any timers that were added using addTimer will actually run. I wrote code to stop adding timers when the game is paused, but that's not related to this issue i'm having.
Clarifying Example
I spawn a monster using addTimer and he materializes on the screen. Within the animation/spawn code, I immediately run addTimer again with a delay of 5 seconds to despawn the monster (so after 5 seconds he leaves).
If I sit there and watch him, he disappears correctly after 5 seconds. If I pause them game, however, (using pauseTimers) below. I wait 5-6 seconds, and unpause the game (using resumeTimers) it immediately runs the despawn animation and removes the monster. So it halted correctly in that I didn't unpause the game and see him gone, but it didn't halt correctly in that it should have continued where the timer left off (i.e. pausing 1 second into it should keep him on the screen 4 seconds).
Problem
Why is the monster disappearing immediately after I pause the game? I thought that if I do timer.suspend that it would stop the timer dead in its tracks, and when I resume it, it will pick up with whatever time was left on the clock?
Any ideas what might be going on here? Thanks so much!
var timers: Dictionary<String, DispatchSourceTimer> = Dictionary<String, DispatchSourceTimer>()
func addTimer(delay: Double, block: @escaping ()->()) {
let queue = DispatchQueue(label: "com.firm.app.timer", attributes: .concurrent)
let myTimer = DispatchSource.makeTimerSource(queue: queue)
//Unique timer key in the dictionary
let timerKey = UUID().uuidString
let time = DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)
myTimer.scheduleOneshot(deadline: time)
//Set the event handler, which is to run my block() code (in this case spawn and despawn of monsters)
//after block finishes, it removes the timer from the dictionary since it's no longer needed.
myTimer.setEventHandler{
block()
if (self.timers.keys.contains(timerKey)) {
self.timers[timerKey]!.cancel()
self.timers.removeValue(forKey: timerKey)
}
}
timers[timerKey] = myTimer //add a new timer for this unique key
myTimer.resume() //for future ref in iOS10 this will be .activate()!
}
///Pause all timers that are currently going on
func pauseTimers()
{
for timer in timers {
timer.value.suspend()
}
}
///Resume all timers so the game can continue
func resumeTimers()
{
for timer in timers {
timer.value.resume()
}
}