How to Clear the timer before running a Selector Function? - swift

I have a timer like this:
var timer = NSTimer.scheduledTimerWithTimeInterval(time, target: self, selector: Selector("finished"), userInfo: nil, repeats: false)
with "time" is NSTimeInterval for running this timer, for example is 10.0 seconds. and "finished" is a function that running when timer is reach 10.0 seconds.
if my timer is running for example when my timer is reach 4.0 seconds, i want to clear or stop the timer or something like that and restart the timer again. How can i do that? I already tried to use:
timer.invalidate()
and recreate the timer again but it still call the "finished" function after that 6.0 seconds.
Please help.

I hope it helps you...
class ViewController: UIViewController {
var timer = NSTimer()
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("result"), userInfo: nil, repeats: true)
}
func result() {
self.elapsedTime++
self.handler(elapsedTime)
if self.elapsedTime == self.duration {
self.stop()
}
}
func stop() {
timer.invalidate()
}

I found a problem, I add more timer than I thought so the other timer still run and take my function.

Related

Swift seconds counter

How can I create a seconds counter which I can stop it and then resume from where I stopped it?
I've create this timer:
func countSeconds() {
secondsTimer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(addSeconds), userInfo: nil, repeats: true)
}
#objc func addSeconds() {
seconds += 1
}
but with invalidate method I don't resume from where I stopped the timer.

swift xcode - disable UIbutton from being pressed once Timer is running

I have a button called start that starts the TIMER counting , I want to disable it from being pressed again when the TIMER is counting other wise it makes the TIMER start counting twice as fast.
#IBAction func start(_ sender: Any) {
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(CountUpVC.action), userInfo: nil, repeats: true)
Thanks in advance.
It's best done with an observer on the timer:
var timer : Timer? {
didSet {
start.isEnabled = !(timer?.isValid ?? false)
}
}
When you invalidate it, you should set it to nil to trigger didSet and enable the button again:
timer?.invalidate()
timer = nil

NSTimer doesn't get fired repeatedly in my Swift code

I scheduled a timer in my viewDidAppear: method, but it just fire once and never fire again, the code is just like below
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
timer = NSTimer(timeInterval: 1, target: self, selector: "test", userInfo: nil, repeats: true)
timer.fire()
}
func test() {
print("timer test")
}
Actually, you didn't schedule it. Try this:
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("test"), userInfo: nil, repeats: true)
And get rid of timer.fire().
Be aware that if you create a timer in viewDidAppear then a new timer will be created every time your view appears.

Swift: How to invalidate a timer if the timer starts from a function?

I have a timer variable in a function like this:
timer = NSTimer()
func whatever() {
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "timerbuiltingo", userInfo: nil, repeats: true)
}
when I try to stop the timer in the resulting timerbuiltingo function like this:
func timerbuiltingo() {
timer.invalidate()
self.timer.invalidate()
}
It doesn't stop it. How should I be doing this?
If you need to be able to stop the timer at any point in time, make it an instance variable.
If you will only ever need to stop it in the method it is called, you can have that method accept an NSTimer argument. The timer calling the method will pass itself in.
class ClassWithTimer {
var timer = NSTimer()
func startTimer() {
self.timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "timerTick:", userInfo: nil, repeats: true)
}
#objc func timerTick(timer: NSTimer) {
println("timer has ticked")
}
}
With this set up, we can now either call self.timer.invalidate() or, within timerTick, we can call timer.invalidate() (which refers to the timer which called the method).

How can I pause and resume NSTimer.scheduledTimerWithTimeInterval in swift?

I'm developing a game and I want to create a pause menu. Here is my code:
self.view?.paused = true
but NSTimer.scheduledTimerWithTimeInterval still running...
for var i=0; i < rocketCount; i++ {
var a: NSTimeInterval = 1
ii += a
delaysShow = 2.0 + ((stimulus + interStimulus) * ii)
var time3 = NSTimer.scheduledTimerWithTimeInterval(delaysShow!, target: self, selector: Selector("showRocket:"), userInfo: rocketid[i], repeats: false)
}
I want time3 to pause the timer when player click pause menu and continue run the timer when player come back to the game, but how can I pause NSTimer.scheduledTimerWithTimeInterval? help me please.
You need to invalidate it and recreate it. You can then use an isPaused bool to keep track of the state if you have the same button to pause and resume the timer:
var isPaused = true
var timer = NSTimer()
#IBAction func pauseResume(sender: AnyObject) {
if isPaused{
timer = NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: Selector("somAction"), userInfo: nil, repeats: true)
isPaused = false
} else {
timer.invalidate()
isPaused = true
}
}
To Start:
timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: Selector("updateView"), userInfo: nil, repeats: true)
To Resume:
timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: Selector("updateView"), userInfo: nil, repeats: true)
To Pause:
timer.invalidate
This worked for me. The trick is that do not look for something like "timer.resume" or "timer.validate". Just use "the same code for starting a timer" to resume it after the pause.
To start
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(ViewController.action), userInfo: nil, repeats: true)
To pause
timer.invalidate()
To reset
time += 1
label.text = String(time)
'label' is the timer on output.
I was just working through a similar problem with my game, and found an easy solution.
First I should point out like others have, that Timer and NSTimer doesn't have a pause function. You have to stop the Timer with Timer.invalidate(). After invalidating a Timer, you must initialize it again to start the Timer. To quote from https://developer.apple.com/documentation/foundation/timer, the function .invalidate() -
Stops the timer from ever firing again and requests its removal from
its run loop.
To pause a timer we can use Timer.fireDate, this is where Timer (and NSTimer) saves the date for when the Timer will fire in the future.
Here's how we can pause a Timer by saving the seconds left that the Timer has until it fires again.
//The variable we will store the remaining timers time in
var timeUntilFire = TimeInterval()
//The timer to pause
var gameTimer = Timer.scheduledTimer(timeInterval: delaysShow!, target: self, selector: #selector(GameClass.showRocket), userInfo: rocketid[i], repeats: false)
func pauseTimer()
{
//Get the difference in seconds between now and the future fire date
timeUntilFire = gameTimer.fireDate.timeIntervalSinceNow
//Stop the timer
gameTimer.invalidate()
}
func resumeTimer()
{
//Start the timer again with the previously invalidated timers time left with timeUntilFire
gameTimer = Timer.scheduledTimer(timeInterval: timeUntilFire, target: self, selector: #selector(GameClass.showRocket), userInfo: rocketid[i], repeats: false)
}
Note: Don't invalidate() the Timer before getting the fireDate. After invalidate() is called the Timer seems to reset the fireDate to 2001-01-01 00:00:00 +0000.
2nd Note: A timer can potentially fire after its set fireDate. This will lead to a negative number, which will default the Timer to run after 0.1 milliseconds instead. https://developer.apple.com/documentation/foundation/timer/1412416-scheduledtimer
To stop it
time3.invalidate()
To start it again
time3.fire()
You can not resume the timer back.
Instead of resuming - just create a new timer.
class SomeClass : NSObject { // class must be NSObject, if there is no "NSObject" you'll get the error at runtime
var timer = NSTimer()
init() {
super.init()
startOrResumeTimer()
}
func timerAction() {
NSLog("timer action")
}
func pauseTimer() {
timer.invalidate
}
func startOrResumeTimer() {
timer = NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector: Selector("timerAction"), userInfo: nil, repeats: true)
}
}
Even though the solutions exposed here are good, I thought an important insight was missing. Like a lot of people here explained, timer invalidate() and recreate is the best option. But one could argue that you could do something like this:
var paused:Bool
func timerAction() {
if !paused {
// Do stuff here
}
}
is easier to implement, but it will be less efficient.
For energy impact reasons, Apple promotes avoiding timers whenever possible and to prefer event notifications. If you really need to use a timer, you should implement pauses efficiently by invalidating the current timer. Read recommendations about Timer in the Apple Energy Efficiency Guide here:
https://developer.apple.com/library/content/documentation/Performance/Conceptual/EnergyGuide-iOS/MinimizeTimerUse.html
SWIFT3
Global Declaration :
var swiftTimer = Timer()
var count = 30
var timer = Timer()
#IBOutlet weak var CountDownTimer: UILabel!
viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
BtnStart.tag = 0
}
Triggered IBACTION :
#IBAction func BtnStartTapped(_ sender: Any) {
if BtnStart.tag == 0 {
BtnStart.setTitle("STOP", for: .normal)
timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(ScoreBoardVC.update), userInfo: nil, repeats: true)
BtnStart.tag = 1
} else {
BtnStart.setTitle("START", for: .normal)
timer.invalidate()
BtnStart.tag = 0
}
}
Function that Handles The things :
func update(){
if(count > 0){
let minutes = String(count / 60)
let ConvMin = Float(minutes)
let minuttes1 = String(format: "%.0f", ConvMin!)
print(minutes)
let seconds = String(count % 60)
let ConvSec = Float(seconds)
let seconds1 = String(format: "%.0f", ConvSec!)
CountDownTimer.text = (minuttes1 + ":" + seconds1)
count += 1
}
}
Pause timer : timer.invalidate()
and
Resume timer : recreate timer. it's work fine.
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(mainController.updateTimer), userInfo: nil, repeats: true)