This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Xcode: Why is my timer count 2 seconds on every tick?
In my app I have a timer that should go from 12:00 to 0:00, but it counts 2 seconds on every tick like this:
11.58
11.56
11.54
11.52 and so on..
this is the code in the start button code:
tid.text=[NSString stringWithFormat:#"%d:%.2d",minuter,sekunder];
timer= [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(tidklick)
userInfo:nil
repeats:YES];
This is the method tidklick:
-(void) tidklick
{
tiden -= 1;
sekunder = tiden % 60;
minuter= (tiden - sekunder) / 60;
tid.text=[NSString stringWithFormat:#"%d:%.2d",minuter,sekunder];
}
This is the code in the beginning..
int tiden=720;
int sekunder;
int minuter;
and also when I hit a certain button, this should happen: i++;
but it seems like i gets added by 2 every time I hit the button....
What is wrong? :S Seems like something with Xcode and not my code?
EDIT: Now I noticed that when I hit the button that should stop the timer in the end(timer invalidate), it counts as normal... It counts one second at a time that is!
Thanks in advance!
For the second part of the question, when you hit your button: Have you made sure that your selector for the button isn't being called twice -- for instance when the button is pressed down and then again when it is lifted up.
When you say you 'hit the button', what is your button hitting code? There are several events that take place on a button "hit" (most notably button down and up events) which if you are not handling properly could increment i multiple times in a single 'hit'.
This could also be the reason the timer is doing down by two instead of one -- when you 'hit' the start button you are launching two timers instead of one, causing one second per timer to be decremented per second.
For better time counting try to use NSDate methods:
[NSDate date] for start value and [NSDate timeIntervalSinceDate:startTime] to get time shift from the start.
Timer firing interval is approximately equals to 1 second.
Related
I am having a simple game with a player, a moving background and moving walls, kinda like flappy bird. My player is able to collect a powerUp. It is transforming after and put into a special level.
I want this level to run for like 10 seconds and then call a backtransformation.
Currently I am using a timer which just calls the backtransformation after 10 seconds. I am having trouble now when the player pauses the game, the timer is still running.
--> what I found on stackoverflow is that you can't resume a timer, you can just invalidate and restart it. This would miss my target, otherwise the player pauses the game every 9 seconds and can stay in the super Level forever.
Do you guys have any idea how I can solve my problem or like an alternative to use Timers in my code?
I appreciate any help
Edit: Here is how I simply used the timer
// transform and go into super level added here
self.transform()
timer = Timer.scheduledTimer(withTimeInterval:10, repeats: false) {
timer in
self.backtransform()
}
When you start the timer record the current time as a Double using
let start = Date().timeIntervalSinceReferenceDate
var remaining = 10.0
When the user pauses the timer, calculate the amount of time that has passed with:
let elapsed = Date().timeIntervalSinceReferenceDate - start
And the amount of remaining time for your timer:
remaining -= elapsed
If the user resumes the timer, set it to remaining, not 10 seconds.
I have this two functions that measure the elapsed time when the phone is locked or the app is in background:
func saveTimeInBackground(){
startMeasureTime = Int(Date.timeIntervalSinceReferenceDate)
}
func timeOnAppActivated(){
stopMeasureTime = Int(Date.timeIntervalSinceReferenceDate)
elapsedTime = stopMeasureTime - startMeasureTime
seconds = seconds - elapsedTime + 2
if seconds > 0 {
timerLbl.text = "time: \(seconds)"
} else {
seconds = 0
timerLbl.text = "time: \(seconds)"
}
}
and then in the viewDidLoad() i have observers that are trigger the functions when the app becomes active/inactive:
NotificationCenter.default.addObserver(self, selector: #selector(saveTimeInBackground), name: Notification.Name.UIApplicationWillResignActive, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(timeOnAppActivated), name: Notification.Name.UIApplicationDidBecomeActive, object: nil)
The problem is that when the app becomes active there are 2 seconds (approximately) of difference so i've added 2 seconds and it seems to work fine, but only if the elapsed time is > 15 seconds.
If i lock the phone and immediately unlock it the there are like 5 or more seconds that are missing. For example, if there are 50 seconds left, when i lock and immediately unlock it there are like 42 seconds left.
Can anyone please explain, what i am doing wrong?
Edit: The logic of the app is this:
It starts a match between 2 players with 60 seconds for a game. The problem is that when one of the players locks the phone the app stop to measure the time. This way if the player1 has 10 seconds left to make a move, the player2 still has 50 seconds left. I'm looking for a reliable way to calculate the time even if the player locks the phone or put the app in background.
Edit 2: I think i figured out what the problem is: I think the issue has to do with the fact that the “seconds” are Int, and the Date not and when it gets converted it’s rounded up. I didn't tested it, but when i ahve the solution i'll post the answer. Thanks all for your time!
You're relying on exact timing of notifications that aren't guaranteed to have any exact timing. There's no guarantee about when, exactly, either of those notifications will arrive, and there's nothing you can do about that. Even your two-second fix is, as you say, approximate. It'll probably be different on different models of iPhone or even at different times on the same iPhone, depending how busy iOS is when you check.
What's more, when you go into the background, you can't be certain that you'll stay there. Once in the background, iOS might decide to terminate your app at any time.
I'm not sure what the goal is here but I think you'll need to reconsider what you want to do and see if there's some other approach. Your current two-second hack will, at best, spawn a bunch of other hacks (like the 15 second threshold you mention) without ever being especially accurate. And then it'll probably all break in the next iOS update when some iOS change causes the timing to change.
I would use Date object to track game time.
func gameStart() {
gameStartDate = Date()
}
func timeOnAppActivated() {
let secondsLeft = 60 - abs(gameStartDate?.timeIntervalSinceNow ?? 0)
if secondsLeft > 0 {
timerLbl.text = "time: \(secondsLeft)"
} else {
timerLbl.text = "time: 0"
}
}
Ok, like I mention in the edit 2 of the question:
The first issue was because "seconds" is a Int and then it almost always gains or lose when converting it from Double.
But the main problem was that i had to invalidate the timer when the app enter in background and i didn't.
So now with invalidating the timer when the app gets the notification that will enter background and then starting it when it enter foreground everything works fine.
To test this properly call those methods on button click. It may be coz of delay in releasing some resources in background.
I am having a label and an array which consists of 10 string values.I know how to display the text in that label.But now,For every 1 minutes I want to display each and every string from that array to the label .Any idea how to do this ?
Use an NSTimer
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:60.0 target:self selector:#selector(changeText:) userInfo:nil repeats:YES];
Remember to use [timer invalidate] if you want to stop the timer, or you'll have a crash if the target has been released.
Add a variable in your class to save the index of current string
Write a method which increase the index and update the label with the next string
Create a NSTimer with interval = 60 seconds to call this method repeatly
Update
Per your comments I guess what you want to update is the location info? Some references:
iOS Multitasking: Background Location
What can we use instead of nstimer?
Location Awareness Programming Guide
iOS App Programming Guide - Tracking the User’s Location
use NSTimer with 60 sec interval, write a method to get the text from the array and display it in the label.
hi i ma new to iphone. what i did is crating a timer and calling a function afer 4 sec intervel. (I write code for timer in viewdidload).Timer will run automatically while application lunch in simulator it self. But i need the timer will start after first 8 sec and timer will repeat for every 4 sec how can i done this pls help me post some code. thank in advance.
take a variable
BOOL isNotFirstTime;
And in the function that gets triggered after each 4 secs add the following code at the starting
-(void)AfterFourSecondsFuction
{
if(!isNotFirstTime)
{
isNotFirstTime=YES;
return;
}
//YOUR CODE HERE...
}
hAPPY cODING...
Use 2 timers. The target of the first 8 second timer can start the second 4 second timer.
Okay, I have searched online and even looked in a couple of books for the answer because I can't understand the apple documentation for the NSTimer. I am trying to implement 2 timers on the same view that each have 3 buttons (START - STOP - RESET).
The first timer counts down from 2 minutes and then beeps.
The second timer counts up from 00:00 indefinitely.
I am assuming that all of the code will be written in the methods behind the 3 different buttons but I am completely lost trying to read the apple documentation. Any help would be greatly appreciated.
Basically what you want is an event that fires every 1 second, or possibly at 1/10th second intervals, and you'll update your UI when the timer ticks.
The following will create a timer, and add it to your run loop. Save the timer somewhere so you can kill it when needed.
- (NSTimer*)createTimer {
// create timer on run loop
return [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(timerTicked:) userInfo:nil repeats:YES];
}
Now write a handler for the timer tick:
- (void)timerTicked:(NSTimer*)timer {
// decrement timer 1 … this is your UI, tick down and redraw
[myStopwatch tickDown];
[myStopwatch.view setNeedsDisplay];
// increment timer 2 … bump time and redraw in UI
…
}
If the user hits a button, you can reset the counts, or start or stop the ticking. To end a timer, send an invalidate message:
- (void)actionStop:(id)sender {
// stop the timer
[myTimer invalidate];
}
Hope this helps you out.
I would follow Jonathan's approach except you should use an NSDate as your reference for updating the UI. Meaning instead of updating the tick based on the NSTimer, when the NSTimer fires, you take the difference between NSDate for now and your reference date.
The reason for this is that the NSTimer has a resolution of 50-100 ms which means your timer can become pretty inaccurate after a few minutes if there's a lot going on to slow down the device. Using NSDate as a reference point will ensure that the only lag between the actual time and the time displayed is in the calculation of that difference and the rendering of the display.