I am making a stopwatch in Objective-C:
- (void)stopwatch
{
NSInteger hourInt = [hourLabel.text intValue];
NSInteger minuteInt = [minuteLabel.text intValue];
NSInteger secondInt = [secondLabel.text intValue];
if (secondInt == 59) {
secondInt = 0;
if (minuteInt == 59) {
minuteInt = 0;
if (hourInt == 23) {
hourInt = 0;
} else {
hourInt += 1;
}
} else {
minuteInt += 1;
}
} else {
secondInt += 1;
}
NSString *hourString = [NSString stringWithFormat:#"%d", hourInt];
NSString *minuteString = [NSString stringWithFormat:#"%d", minuteInt];
NSString *secondString = [NSString stringWithFormat:#"%d", secondInt];
hourLabel.text = hourString;
minuteLabel.text = minuteString;
secondLabel.text = secondString;
[NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:#selector(stopwatch) userInfo:nil repeats:YES];
}
The stopwatch has three separate labels, if you were wondering, for hours, minutes and seconds. However, instead on counting by 1, it counts like 2, 4, 8, 16, etc.
Also, another issue with the code (quite a minor one) is that it doesn't display all numbers as two digits. For example it's shows the time as 0:0:1, not 00:00:01.
Any help is really appreciated! I should add that I am really new to Objective-C so keep it as simple as possible, thank you!!
Don't use repeats:YES if you schedule the timer at every iteration.
You're spawning one timer at every iteration and the timer is already repeating, resulting in an exponential growth of timers (and consequently of method calls to stopwatch).
Change the timer instantiation to:
[NSTimer scheduledTimerWithTimeInterval:1.0f
target:self
selector:#selector(stopwatch)
userInfo:nil
repeats:NO];
or start it outside the stopwatch method
For the second issue simply use a proper format string.
NSString *hourString = [NSString stringWithFormat:#"%02d", hourInt];
NSString *minuteString = [NSString stringWithFormat:#"%02d", minuteInt];
NSString *secondString = [NSString stringWithFormat:#"%02d", secondInt];
%02d will print a decimal number padding it with 0s up to length 2, which is precisely what you want.
(source)
For the first issue, instead of creating a timer instance for every call.Remove the line
[NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:#selector(stopwatch) userInfo:nil repeats:YES];
from the function stopwatch.
Replace your call to function stopwatch with the line above. i.e replace
[self stopwatch]
with
[NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:#selector(stopwatch) userInfo:nil repeats:YES];
Related
I have added a simple timer in my app. At the moment the timer is just going from 00:00, 00:01, 00:02 and so on. When i complete a level i got to result screen which displays my score. Im still quite new to this and i was wondering how can i display the timer results.
This is the implementation of the timer:
//in .h file
IBOutlet UILabel *GameTimer;
int timeSec;
int timeMin;
NSTimer *timer;
//in .m file
-(void)startTimer1{
//Invalidate function stops 'timer1' before it is restarted
//initializing 'timer1'
timer1 = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(timerTick:)
userInfo:nil
repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer1 forMode:NSDefaultRunLoopMode];
}
//Event called every time the NSTimer ticks.
- (void)timerTick:(NSTimer *)timer1
{
timeSec++;
if (timeSec == 60)
{
timeSec = 0;
timeMin++;
}
//Format the string 00:00
NSString* timeNow = [NSString stringWithFormat:#"%02d:%02d", timeMin, timeSec];
//Display on your label
//[timeLabel setStringValue:timeNow];
GameTimer.text= timeNow;
}
My attempt to display it on results screen but all i get is 0(dont mind the Spanish string just says how many points you got):
pointsInfo.text = [NSString stringWithFormat:#"¡Felicidades! ¡Has conseguido la máxima puntuación: %#! Debajo puedes encontrar las respuestas que has seleccionado:, time results: %# ",sc, timer1];
EDIT: Game1 is a viewController and so is gameResults1.
Game1 method:
// Method for starting 'timer1'
-(void)startTimer1{
//Invalidate function stops 'timer1' before it is restarted
//initializing 'timer1'
timer1 = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(timerTick:)
userInfo:nil
repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer1 forMode:NSDefaultRunLoopMode];
}
//Event called every time the NSTimer ticks.
- (void)timerTick:(NSTimer *)timer1
{
timeSec++;
if (timeSec == 60)
{
timeSec = 0;
timeMin++;
}
//Format the string 00:00
timeNow = [NSString stringWithFormat:#"%02d:%02d", timeMin, timeSec];
//Display on your label
//[timeLabel setStringValue:timeNow];
GameTimer.text= timeNow;
}
//Call this to stop the timer event(could use as a 'Pause' or 'Reset')
- (void) StopTimer
{
[timer invalidate];
timeSec = 0;
timeMin = 0;
//Since we reset here, and timerTick won't update your label again, we need to refresh it again.
//Format the string in 00:00
timeNow = [NSString stringWithFormat:#"%02d:%02d", timeMin, timeSec];
//Display on your label
// [timeLabel setStringValue:timeNow];
GameTimer.text= timeNow;
}
// #selector for 'timer1'
I dont think i have any particular way in calling game1 in gameresults1. other than:
#interface Game1Results : Game1
Create a global variable
#interface YourViewController ()
{
NSString *timeNow;
}
Now use this in your timerTick method.
timeNow = [NSString stringWithFormat:#"%02d:%02d", timeMin, timeSec];
At the end, display score as
pointsInfo.text = timeNow;
The timer value is stored in timeMin and timeSec. You just have to get the timeMin and timeSec values to get your timer value.
NSString * resultTimer = [NSString stringWithFormat:#"%02d:%02d", timeMin, timeSec];
NSLog(#"%#",resultTimer);
EDIT:
You can also implement a method stringValue :
-(NSString*)stringValue{
return [NSString stringWithFormat:#"%02d:%02d", timeMin, timeSec];
}
And call the method
[yourtimer stringValue];
i cant seem to get my NSTimer to stop when it reaches 0 i've looked around for an answer and i tryed everything please help.
-(void)count {
mainint -= 1;
seconds.text = [NSString stringWithFormat:#"%i", mainint];
}
-(IBAction)start:(id)sender {
play.hidden = YES;
mainint = 60;
timer1 = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(count) userInfo:nil repeats:YES];
if (timer1 == 0) {
[timer1 invalidate];
timer1 = nil;
}
}
put your if condition in count() function
-(void)count {
mainint -= 1;
seconds.text = [NSString stringWithFormat:#"%i", mainint];
if (mainint == 0) {
[timer1 invalidate];
}
}
The issue is that your timer will never be nil (0) unless you set it yourself to nil. I think what you're trying to achieve is something like this :
-(void)count {
mainint -= 1;
seconds.text = [NSString stringWithFormat:#"%i", mainint];
if (mainint <= 0) {
[timer1 invalidate];
timer1 = nil;
}
}
I have an iPhone app which is basically a clock, stopwatch, and timer. Everything works fine, until you leave the app, and the stopwatch and timer stop counting. I think the way to solve this would be to start a counter when the app is put into the background, and add/subtract that from the stopwatch/timer when the app starts up again. Is this the best thing to do, and if so, how would I do this?
UPDATE: The timer, stopwatch, and clock are all in different view controllers. Here is the code for my stopwatch in StopwatchViewController.m:
- (void)stopwatch // Start counting the stopwatch
{
hourInt = [hourLabel.text intValue]; // Store integer values of time
minuteInt = [minuteLabel.text intValue];
secondInt = [secondLabel.text intValue];
if (secondInt == 59) { // Add on one second
secondInt = 0;
if (minuteInt == 59) {
minuteInt = 0;
if (hourInt == 23) {
hourInt = 0;
} else {
hourInt += 1;
}
} else {
minuteInt += 1;
}
} else {
secondInt += 1;
}
NSString *hourString = [NSString stringWithFormat:#"%02d", hourInt]; // Update text to show time
NSString *minuteString = [NSString stringWithFormat:#"%02d", minuteInt];
NSString *secondString = [NSString stringWithFormat:#"%02d", secondInt];
hourLabel.text = hourString;
minuteLabel.text = minuteString;
secondLabel.text = secondString;
[NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:#selector(stopwatch) userInfo:nil repeats:NO]; // Repeat every second
}
How do I get it to add on the elapsed time the app was in the background?
Add two observers for when app enter in background and for app enterForeGround
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(applicationWillEnterInBackGround) name:UIApplicationWillResignActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(applicationWillEnterInForeground) name:UIApplicationWillEnterForegroundNotification object:nil];
- (void)applicationWillEnterInBackGround{
// stop your timer here
}
- (void)applicationWillEnterInForeground
{
// start your timer here
}
Example ------
in .h
NSTimer *timer;
float time;
in .m
- (void)viewDidLoad
{
[super viewDidLoad];
timer=[NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:#selector(stopwatch) userInfo:nil repeats:YES];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(applicationWillEnterInBackGround) name:UIApplicationWillResignActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(applicationWillEnterInForeground) name:UIApplicationWillEnterForegroundNotification object:nil];
}
- (void)applicationWillEnterInBackGround
{
[timer invalidate];
}
- (void)applicationWillEnterInForeground
{
timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:#selector(stopwatch) userInfo:nil repeats:YES];
}
- (void)stopwatch // Start counting the stopwatch
{
hourInt = [hourLabel.text intValue]; // Store integer values of time
minuteInt = [minuteLabel.text intValue];
secondInt = [secondLabel.text intValue];
if (secondInt == 59) { // Add on one second
secondInt = 0;
if (minuteInt == 59) {
minuteInt = 0;
if (hourInt == 23) {
hourInt = 0;
} else {
hourInt += 1;
}
} else {
minuteInt += 1;
}
} else {
secondInt += 1;
}
NSString *hourString = [NSString stringWithFormat:#"%02d", hourInt]; // Update text to show time
NSString *minuteString = [NSString stringWithFormat:#"%02d", minuteInt];
NSString *secondString = [NSString stringWithFormat:#"%02d", secondInt];
hourLabel.text = hourString;
minuteLabel.text = minuteString;
secondLabel.text = secondString;
}
The easiest way to proceed and save the current time when the application goes to background and then when come back to foreground compute the time interval and add it to your counters, something like:
.. going background ..
NSDate *backgroundTime = [[NSDate date] retain];
.. returning foreground ..
NSTimeInterval elapsed = [NSDate timeIntervalSinceDate:date];
[date release];
yourTimer -= elapsed;
To understand when exactly you should hook these events you should take a look here.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to Pause/Play NSTimer?
I have three buttons start stop and pause..My start and stop button is working fine with the below code..but when press Pause it pause the timer..but when again i Press start.IT continues from the new added time ...not from the pause time....
supoose i pause at 5 second of start and wait for 5 sec then press start...it should display 5 ...but displaying 10..
because I have not mentioned (timer:) in timer!=nill of start...
how it will be add..
I have problems:
Pause not working.
-(void)start:(NSTimer *)timer
{
if(_timer==nil)
{
startDate =[NSDate date];
_timer=[NSTimer scheduledTimerWithTimeInterval:0.25 target:self selector:#selector(timer:) userInfo:nil repeats:YES];
}
if(_timer!=nil)
{
float pauseTime = -1*[pauseStart timeIntervalSinceNow];
[_timer setFireDate:[previousFireDate initWithTimeInterval:pauseTime sinceDate:previousFireDate]];
}
}
-(void)timer:(NSTimer *)timer
{
NSInteger secondsSinceStart = (NSInteger)[[NSDate date] timeIntervalSinceDate:startDate];
NSInteger seconds = secondsSinceStart % 60;
NSInteger minutes = (secondsSinceStart / 60) % 60;
NSInteger hours = secondsSinceStart / (60 * 60);
NSString *result = nil;
if (hours > 0)
{
result = [NSString stringWithFormat:#"%02d:%02d:%02d", hours, minutes, seconds];
}
else
{
result = [NSString stringWithFormat:#"%02d:%02d", minutes, seconds];
}
label.text=result;
NSLog(#"time interval -> %#",result);
}
-(void)stop
{
if(_timer!=nil)
{
startDate=nil;
[_timer invalidate];
_timer = nil;
}
}
-(void)pause:(NSTimer *)timer
{
pauseStart = [NSDate dateWithTimeIntervalSinceNow:0];
previousFireDate = [_timer fireDate];
[_timer setFireDate:[NSDate distantFuture]];
}
-(void)pause:(NSTimer *)timer
{
pauseStart = [NSDate dateWithTimeIntervalSinceNow:0];
previousFireDate = [_timer fireDate];
//[timer setFireDate:[NSDate distantFuture]];
[_timer setFireDate:[NSDate distantFuture]];
}
Here is the code that I used for a timer:
I store all the components for the time, in my (singleton) class, the hour, minute, seconds value.
And, I simply "invalidate" the timer in the "pause" method, AND I store the values.
See, if this helps.
-(void) startTimer
{
NSLog(#"Values for timer: %d H, %d M, %d S", self.hours, self.minutes, self.seconds);
_timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:#selector(updateTimer) userInfo:nil repeats:YES];
}
-(void) pauseTimer
{
if(_timer)
{
[_timer invalidate];
}
_timer = nil;
self.hour = hourValue;
self.minute = minuteValue;
self.second = secondsValue;
}
I've been trying to create a script that sets a timer and reduces a value by 33 each time it runs. In theory the timer should stop itself after 6 runs, but it keeps going and reaches negative values. Is there a reason for this?
-(void)checkValue:(NSTimer *)myTimer{
if(pplint > 0){
pplint = pplint-33;
NSString *ppllefttext = [NSString stringWithFormat:#"%d", pplint];
peopleleft.text = ppllefttext;
NSLog(#"Reduced Timer");
}
if(pplint < 0){
NSLog(#"Stop Timer");
[myTimer invalidate];
}
}
- (IBAction)gotocongrats{
pplint = 198;
NSString *ppllefttext = [NSString stringWithFormat:#"%d", pplint];
peopleleft.text = ppllefttext;
NSTimer * myTimer = [NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:#selector(checkValue:)
userInfo:nil
repeats:YES];
NSLog(#"Started Timer");
}
I took you code and edited it a bit and it works just fine for me.
-(void)checkValue:(NSTimer *)myTimer{
if(pplint > 0){
pplint = pplint-33;
NSLog(#"%i",pplint);
NSLog(#"Reduced Timer");
}
if(pplint <= 0){
NSLog(#"Stop Timer");
[myTimer invalidate];
}
}
- (IBAction)gotocongrats{
pplint = 198;
NSTimer * myTimer = [NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:#selector(checkValue:)
userInfo:nil
repeats:YES];
NSLog(#"Started Timer");
}