Probably a simple question, however, I can't seem to conceive an elegant approach.
I want to design a trivial application that allows a timer to be set to a duration (say 1 minute), after that duration the timer should expire, in the duration the timer should update the UI every second.
Thus if the timer is set to one minute, the timer should fire, update the UI every second (by calling a method) and then finally invalidate after 1 minute.
My conundrum is, I can set a scheduledTimerWithInterval, it calls a method on the timer interval. If I make this 1 minute I can call a method after one minute to invalidate the timer, but there doesn't seem to be a mechanism to perform calls during this minute.
Can you give me some guidance?
I would have done something like this:
1: Declare a timer and a counter:
var timer = Timer()
var counter = 0
2: Create a new function called for example startEverySecond that starts the timer with one second interval, this function is called after 60 seconds and will be called for 1 minute and then invalidate:
func startEverySecond() {
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(everySecond), userInfo: nil, repeats: true)
}
func everySecond(){
if counter == 60{
timer.invalidate()
}
counter = counter + 1
print("Second")
}
3: Handle the start and stop of the timer:
// Start with 60 second interval
timer = Timer.scheduledTimer(timeInterval: 60, target: self, selector: #selector(startEverySecond), userInfo: nil, repeats: false)
// Stop
timer.invalidate()
So basically when you start your timer it will start off with 60 seconds and when this is done it will call the function startEverySecondand this will change the timer to call the everySecondfunction every second for 1 minute. To stop the timer just call timer.invalidate()
Swift 3.x code
Make two global variables
var seconds = 1
var secondTimer:Timer?
Then make these two functions
// for setup of timer and variable
func setTimer() {
seconds = 1
secondTimer?.invalidate()
secondTimer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(updateUI), userInfo: nil, repeats: true)
}
//method to update your UI
func updateUI() {
//update your UI here
//also update your seconds variable value by 1
seconds += 1
if seconds == 60 {
secondTimer?.invalidate()
secondTimer = nil
}
print(seconds)
}
finally call setTimer() wherever you want
Related
I'm trying to update a countdown timer on my UI that counts down in minutes, so I need to update it every start of a new minute, which is not the same as updating every minute. My current solution is initializing a timer that calls the updateUI() function every tenth of a second, which is far from ideal:
timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector:#selector(TimesViewController.updateUI), userInfo: nil, repeats: true)
Is there a way to call that function every start of a new minute?
Create timer that checks system date in each second. For example;
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { (_) in
let second = Calendar.current.component(.second, from: Date())
if second == 0 {
// new minute
updateUI()
}
}
I declared delay and it is giving me an error, I am trying to slow down the timer.
//Updates Timer
func updateTimer() {
var delay: Int
seconds += 1
self.timerLabel.text = String(self.seconds * 0.01)
timer = NSTimer.scheduledTimerWithTimeInterval(-2.0, target: self, selector: #selector(GameScene.delay), userInfo: nil, repeats: false)
The message is telling you that there is no selector for GameScene.delay. You need a func that matches this name. Note that because you have used "GameScene" rather than "gameScene", it may be a class, in which case you would need a "class func" called delay. However, more likely is you would want "self.delay" to be called. ie. one of
func delay(timer: NSTimer) { ... }
class func delay(timer: NSTimer) { ... }
Also, what are you trying to achieve with "-2.0"? You can't run a timer in the past - if will default to 0.1 if <= 0.
the selector portion of a NSTimer is meant to run a function so you declare the function then the timer should be placed outside of the function instead of inside the function
func updateTimer() {
var delay: Int
seconds += 1
self.timerLabel.text = String(self.seconds * 0.01)}
let timer = NSTimer.scheduledTimerWithTimeInterval(2.0, target: self, selector: #selector(self.updateTimer), userInfo: nil, repeats: false)
also could you be more specific when you say you are trying to slow down the timer so
How can I iterate a for loop overtime in swift? A typical loop will execute immediately as fast as possible. However, I would like to expand the time in which the loop occurs.
Say I have the following loop:
for var i = 0; i < 4; i+=1{
print(i)
}
And I wanted this loop to occur over a span of 1 second, each iteration taking 0.25 seconds. How could I do this? Thanks for any help
You might want to create a Timer like this:
timer = NSTimer.scheduledTimerWithTimeInterval(0.25, target: self, selector: #selector(MyClass.tic), userInfo: nil, repeats: true)
time.fire() //first time
this timer will call the function selected with #selector when it fires, and will fire every 0.25 secondes (first parameter) until you invalidate it. So when you have ended your loops you can
call timer.invalidate()
tic() is a function you can define, and can have any name you want:
func tic() {
numberOfTimeFired = numberOfTimeFired + 1
print(numberOfTimeFired)
}
In Swift 3 the timer declaration would be:
timer = Timer.scheduledTimer(timeInterval: 0.25, target: self, selector: #selector(MyClass.tic), userInfo: nil, repeats: true)
I have just started to learn swift 2 and I am testing a few things in an Xcode 'playground'. When a create an instance of the 'pyx' (below) I am not seeing the console output I would expect. I am sure I have made a silly mistake but after staring at it for a while I cannot figure it out.
class zxy {
var gameTimer = NSTimer()
var counter = 0
init() {
gameTimer = NSTimer (timeInterval: 1, target: self, selector: "Run:", userInfo: nil, repeats: true)
}
func Run(timer : NSTimer) {
while(counter < 10){
print(counter)
counter++
}
timer.invalidate()
}
}
Thanks in advanced.
You have 2 problems with your code. As #glenstorey points out in his answer, you need to call the method scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:, not the init method you're calling.
EDIT:
As #DanBeauleu says in his comment to my answer, the call would look like this in Swift:
NSTimer.scheduledTimerWithTimeInterval(
1,
target: self,
selector: "Run:",
userInfo: nil,
repeats: true)
The second problem is your Run method.
You don't want a while loop. That will repeat 10 times in a tiny fraction of a second the first time the timer fires, then invalidate the timer.
Your timer method needs to be changed like this:
func Run(timer : NSTimer)
{
if counter < 10
{
print(counter)
counter++
}
else
{
timer.invalidate()
}
}
(BTW, by strong convention, method/function names should start with a lower-case letter, so your Run function should be named run instead.)
You've created a NSTimer object, but that doesn't start the timer - just gets it ready to go. Use scheduledTimerWithTimeInterval to create and start the timer.
I am trying to create a timer to countdown x minutes and y seconds.
I am computing the number of seconds and creating the InterfaceTimer like this:
timer.setDate(NSDate(timeIntervalSinceNow:Double(secondsValue+1)))
timer.stop()
after that I keep stoping it and starting it again and again, but the values are suddenly decreasing as "time(now) doesn't stop".
Eg: if the timer shows :55, I start it for 3sec and stop it, it shows :52, I wait 10seconds and then start it again, it starts from :42.
I can not save the value currently in the WKInterfaceTimer, so that I could start again from the same point. Everything I tried doesn't work. Did anyone work with the timer and it stayed at the same value after stopping it?
Yes the watchkit timer is a bit...awkward...and definitely not very intuitive. But that's just my opinion
You'll have to keep setting the date/timer each time the user chooses to resume the timer.
Remember, you'll also need an internal NSTimer to keep track of things since the current WatchKit timer is simply for display without having any real logic attached to it.
So maybe something like this...It's not elegant. But it works
#IBOutlet weak var WKTimer: WKInterfaceTimer! //watchkit timer that the user will see
var myTimer : NSTimer? //internal timer to keep track
var isPaused = false //flag to determine if it is paused or not
var elapsedTime : NSTimeInterval = 0.0 //time that has passed between pause/resume
var startTime = NSDate()
var duration : NSTimeInterval = 45.0 //arbitrary number. 45 seconds
override func willActivate(){
super.willActivate()
myTimer = NSTimer.scheduledTimerWithTimeInterval(duration, target: self, selector: Selector("timerDone"), userInfo: nil, repeats: false)
WKTimer.setDate(NSDate(timeIntervalSinceNow: duration ))
WKTimer.start()
}
#IBAction func pauseResumePressed() {
//timer is paused. so unpause it and resume countdown
if isPaused{
isPaused = false
myTimer = NSTimer.scheduledTimerWithTimeInterval(duration - elapsedTime, target: self, selector: Selector("timerDone"), userInfo: nil, repeats: false)
WKTimer.setDate(NSDate(timeIntervalSinceNow: duration - elapsedTime))
WKTimer.start()
startTime = NSDate()
pauseResumeButton.setTitle("Pause")
}
//pause the timer
else{
isPaused = true
//get how much time has passed before they paused it
let paused = NSDate()
elapsedTime += paused.timeIntervalSinceDate(startTime)
//stop watchkit timer on the screen
WKTimer.stop()
//stop the ticking of the internal timer
myTimer!.invalidate()
//do whatever UI changes you need to
pauseResumeButton.setTitle("Resume")
}
}
func timerDone(){
//timer done counting down
}