I'm trying to make a game in which the user completes a task in the fastest time possible, and I want to display the user's best time, and update it every time he gets a better time. I have the following code. How do I ensure BestTimeValue isn't always setting to zero?
float starttime
float BestTimeValue
-(void)timer2{
starttime = 0.0f;
timer2 = [NSTimer scheduledTimerWithTimeInterval:1/1000.0f
target:self
selector:#selector(start)
userInfo:nil
repeats:YES]; }
-(void)start{
starttime += 0.001;
timelabel.text = [NSString stringWithFormat:#"%.3f", starttime];
}
- (void)viewDidLoad
{
BestTimeValue = [[NSUserDefaults standardUserDefaults] floatForKey:#"BestTimeSaved"];
BestTime.text = [NSString stringWithFormat:#"Best Time: %.3f", BestTimeValue]; }
And when the game ends:
[timer2 invalidate];
if (starttime < BestTimeValue) {
[[NSUserDefaults standardUserDefaults] setFloat:starttime forKey:#"BestTimeSaved"];
}
[[NSUserDefaults standardUserDefaults] synchronize];
}
Related
I am new to IOS.I want to user countdown timer.I mean If it set timer for 5 min then after 5 min a function should call so I am using NSTimer for that and I will show min and seconds in a label so after 5 min the label will start from 0 min so it is perfectly working when my app is in foreground when when my app go to background NSTimer will not work after 3 min so when ever I am going I am background I am save time and second in NSUserDefault and I am assigning that values to label when it comes to foreground but the timer is not showing perfectly
-(void) StartTimer
{
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(timerTick:) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
}
- (void)timerTick:(NSTimer *)timer
{
timeSec++;
if (timeSec >= 60)
{
timeSec = timeSec-60;
timeMin++;
}
// else
// {
// [self StopTimer];
// }
//Format the string 00:00
NSString* timeNow = [NSString stringWithFormat:#"%02d:%02d", timeMin, timeSec];
//Display on your label
//[timeLabel setStringValue:timeNow];
self.lblForTimer.text= timeNow;
NSNumber *numberValue = [NSNumber numberWithInt:[user.timerInterval intValue]];
if (timeMin>= [numberValue intValue])
{
timeMin = 0;
timeSec++;
}
}
//Call this to stop the timer event(could use as a 'Pause' or 'Reset')
- (void) StopTimer
{
[timer invalidate];
timer=nil;
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
NSString* timeNow = [NSString stringWithFormat:#"%02d:%02d", timeMin, timeSec];
//Display on your label
// [timeLabel setStringValue:timeNow];
self.lblForTimer.text= timeNow;
}
- (void)appWillEnterForeground:(NSNotification *)notification {
NSLog(#"will enter foreground notification");
}
- (void)applicationDidEnterBackground:(NSNotification *)notification {
NSLog(#"did enter backgroun notification");
NSLog(#"%d,%d",timeMin,timeSec);
NSDate *currentDate= [NSDate date];
[[NSUserDefaults standardUserDefaults] setObject:currentDate forKey:#"backgroundDate"];
[[NSUserDefaults standardUserDefaults] setInteger:timeSec forKey:#"sec"];
[[NSUserDefaults standardUserDefaults] setInteger:timeMin forKey:#"min"];
[[NSUserDefaults standardUserDefaults] synchronize];
[self StopTimer];
}
- (void)appDidBecomeActive:(NSNotification *)notification {
NSDate *dateWhenAppGoesBg= (NSDate *)[[NSUserDefaults standardUserDefaults] objectForKey:#"backgroundDate"];
NSTimeInterval timeSpentInBackground = [[NSDate date] timeIntervalSinceDate:dateWhenAppGoesBg];
int timeMinBack=floor(timeSpentInBackground/60);
int timeSecBack=round(timeSpentInBackground - timeMinBack * 60);
NSLog(#"%d%d",timeMinBack,timeSecBack);
// timeMin=(int)[[NSUserDefaults standardUserDefaults] integerForKey:#"min"]+timeMinBack;
timeMin=[user.counterValue intValue];
// timeSec=(int)[[NSUserDefaults standardUserDefaults] integerForKey:#"sec"]+timeSecBack;
if (timeMin>0) {
timeSec=timeSecBack;
}
else
{
timeSec=(int)[[NSUserDefaults standardUserDefaults] integerForKey:#"sec"]+timeSecBack;
}
NSLog(#"timme sec %d",timeSec);
[self StartTimer];
}
this is my code for implementing countdown timer its perfectly working in foreground but when it comes to forground from background timer values is nit perfect there is 1 min of gap between timer cananyone help me out in this issue
You can save currentDate as property. Don't need to use NSUserDefaults in this case.
Save and manipulate your timeout just in seconds and when needed retranslate as so:
NSInteger min = self.timeout / 60;
NSInteger sec = self.timeout % 60;
I have this code to change the number in the NSString every five seconds.
How will I keep the numbers running in a loop? It now runs from 1 to 19 ,and stops at the last one (19) with a SIGABRT on the line: label.text = ...
How can I start with the first number displayed (0), before the first timer fires?
Here is the code:
-(IBAction) rotate3
{
NSString *number = [self.dayArray description];
NSArray *array = [[NSArray alloc] initWithObjects: #"0", #"1", #"2",..., #"19",nil];
number = #"0" ;
numberCount++ ;
self.dayArray = array;
[array release];
label.text = [NSString stringWithFormat:#"Day: %# ", [dayArray objectAtIndex :numberCount ]];
}
//and the timer
- (void)viewDidLoad
{
timer=[NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:#selector(rotate3 )userInfo:nil repeats:YES];
}
Here is my answers:
1)I think, at the last one (19), the numberCount is 20 (numberCount++ ;).
2)Just set the value before scheduling the timer.
add this to your .h file, in your interface (that is, if it isn't already there)
{
NSInteger numberCount
}
Then in your viewDidLoad method, initialize numberCount and the label:
numberCount = 0;
label.text = #"0";
And in your time method, replace:
numberCount++
with
if(numberCount++ > 19)
numberCount = 0;
What is the "number" NSString used for, b.t.w.?
Why have dayArray?
why not something like
label.text = [NSString stringWithFormat:#"Day: %d", numberCount++];
if (numberCount>19) numberCount = 0;
I don't know what you have number count initialized to it should probably be -1 and also reinitialized to -1 . if you wish to iterate thru "Day: 0" ... "Day: 19"
It's not clear.
You could change the -(void)viewDidLoad timer to not repeat
timer=[NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:#selector(rotate3 )userInfo:nil repeats:NO];
then, conditionally set it up again in the rotate3 method if you still want to change the text 5 seconds later.
try this:
#pragma mark - timer callback
-(IBAction)rotate3
{
[label1 setText:[dayArray objectAtIndex:numberCount]];
numberCount++;
if (numberCount >= [dayArray count])
numberCount = 0;
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
dayArray = [[NSArray alloc] initWithObjects:#"0",#"1",#"2",#"3", nil];
[label1 setText:[dayArray objectAtIndex:0]];
numberCount = 1;
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(rotate3) userInfo:nil repeats:YES];
// Do any additional setup after loading the view, typically from a nib.
}
HI I have already created a countdown in second, lets say 10 second, but I want to make it more precise
to 10.0 and display it on a label, how do it do that? Thanks in advance
This is what I have now for the "second" countdown
my NSTimer
counterSecond = 10
NSTimer timer1 = [NSTimer scheduledTimerWithTimeInterval : 1
Target:self selector:#selector (countLabel) userInfo:nil repeats:YES];
-(void)countLabel:
counterSecond --;
self.timerLabel.text = [NSString stringWithFormat #"%d", counterSecond];
I would use a start date/time to keep track of the countdown. Because iOS can delay firing the timer for other tasks.
- (void)countdownUpdateMethod:(NSTimer*)theTimer {
// code is written so one can see everything that is happening
// I am sure, some people would combine a few of the lines together
NSDate *currentDate = [NSDate date];
NSTimeInterval elaspedTime = [currentDate timeIntervalSinceDate:startTime];
NSTimeInterval difference = countdownSeconds - elaspedTime;
if (difference <= 0) {
[theTimer invalidate]; // kill the timer
[startTime release]; // release the start time we don't need it anymore
difference = 0; // set to zero just in case iOS fired the timer late
// play a sound asynchronously if you like
}
// update the label with the remainding seconds
countdownLabel.text = [NSString stringWithFormat:#"Seconds: %.1f", difference];
}
- (IBAction)startCountdown {
countdownSeconds = 10; // Set this to whatever you want
startTime = [[NSDate date] retain];
// update the label
countdownLabel.text = [NSString stringWithFormat:#"Seconds: %.1f", countdownSeconds];
// create the timer, hold a reference to the timer if we want to cancel ahead of countdown
// in this example, I don't need it
[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector (countdownUpdateMethod:) userInfo:nil repeats:YES];
// couple of points:
// 1. we have to invalidate the timer if we the view unloads before the end
// 2. also release the NSDate if don't reach the end
}
counterSecond = 10
NSTimer timer1 = [NSTimer scheduledTimerWithTimeInterval : 0.1
Target:self selector:#selector (countLabel) userInfo:nil repeats:YES];
-(void)countLabel:
counterSecond - 0.1;
self.timerLabel.text = [NSString stringWithFormat #"%f", counterSecond];
That should work.
I am writing a countdowtimer application like the timer tab in the clock app of the iPhone. Right now I am having trouble comparing to dates, the 'now' and 'futureDate'.
all the variables are synthesized and are nonatomic and retain.
I have this code right now.
- (IBAction)startTimer:(id)sender {
NSLog(#"startTimer");
pickerView.hidden = YES;
labelView.hidden = NO;
now = [[NSDate alloc] init];
futureDate = [[NSDate alloc] initWithTimeInterval:picker.countDownDuration sinceDate:now];
NSLog(#"Dates.\nNow = (%#) \nfutureDate (%#)", now, futureDate);
timerLabelUpdater = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(labelUpdater) userInfo:nil repeats:YES];
}
- (void)labelUpdater {
if ([now timeIntervalSinceDate:futureDate] < 0.0) {
NSLog(#"YES\nDates.\nNow = (%#) \nfutureDate (%#)", now, futureDate);
} else {
NSLog(#"NO\nNow = (%#) \nfutureDate (%#)", now, futureDate);
}
}
Debugger info:
2011-02-08 16:46:02.449 App[22504:207] startTimer
2011-02-08 16:46:02.451 App[22504:207] Dates.
Now = (2011-02-08 18:46:02 +0000)
futureDate (2011-02-08 18:47:02 +0000)
2011-02-08 16:46:03.451 App[22504:207] YES
And it stay giving me yes "forever".
But if you see the variable hours, they are +2h in the future compared from my clock time. Is this the bug?
Sorry my if was testing the wrong date, comparing the variable now and futureDate the time interval will be the same forever. I replaced the now variable for a [[NSDate alloc] init] in the test. Right now the code works.
if ([[[NSDate alloc]init] timeIntervalSinceDate:futureDate] < 0.0) {
NSLog(#"YES\nDates.\nNow = (%#) \nfutureDate (%#)", now, futureDate);
} else {
NSLog(#"NO\nNow = (%#) \nfutureDate (%#)", now, futureDate);
}
sorry for the stupid question.
I constantly get malloc error : double freed....
The echoTime function is being called by a button. When I press the button again before the timer ends it gives me the malloc error. When I press the button after the timer finished to start it again, the simulator hangs.
Does anyone know what is wrong with the following piece of code:
-(IBAction)echoTime: (id) sender {
if (gameTimer != nil) {
[gameTimer invalidate];
[gameTimer release];
}
NSInteger secs = 1 * 60;
if (secs != 0) {
NSNumber *elapsedSeconds = [[NSNumber alloc] initWithInt:secs];
NSDictionary *myDict = [NSDictionary dictionaryWithObject:elapsedSeconds forKey:#"TotalSeconds"];
gameTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(echoIt:) userInfo:myDict repeats: YES];
}
}
-(void)echoIt: (NSTimer *) timer {
NSNumber *num = (NSNumber *) [[timer userInfo] valueForKey:#"TotalSeconds"];
seconds++;
NSInteger sec = [num integerValue] - seconds;
NSInteger minutes = sec / 60;
[gameTimeLabel setText:[NSString stringWithFormat:#"%02i:%02i", minutes, sec-(60*minutes)]];
if (sec == 0) {
[self playSound:#"Horn"];
[gameTimer invalidate];
}
}
NSNumber *elapsedSeconds = [[NSNumber alloc] initWithInt:secs];
In general dont alloc NSNumbers and a NSDictionary (and NSArray,NSSet) always retains the objects it is given (and releases them too when it should).
try...
NSNumber *elapsedSeconds = [NSNumber numberWithInt:secs];
It'll stop the retain cycle you've got and might stop the crash.
Also irrelevant but stylewise.
NSInteger secs = [[[timer userInfo] valueForKey:#"TotalSeconds"] intValue];
Is a little more efficient.