I've created a countdown timer and it works great.. but when it reaches zero it continues counting down.. so it shows -1, -2, -3 etc. How do I prevent it from doing this?
This is my code from the implementation file..
#implementation ViewController
-(IBAction)start {
myTicker = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(showActivity) userInfo:nil repeats:YES];
}
-(IBAction)stop {
[myTicker invalidate];
}
-(IBAction)reset {
time.text = #"0";
}
-(void)showActivity {
int currentTime = [time.text intValue];
int newTime = currentTime -1;
time.text = [NSString stringWithFormat:#"%d", newTime];
}
I'm guessing that I'm missing some code somewhere?
Quick fix is to change:
int newTime = currentTime - 1;
into:
int newTime = (currentTime > 0) ? currentTime - 1 : 0;
That will stop the countdown timer from going below zero. If that's all you need, that should suffice.
It won't turn off the timer or execute an action when it reaches zero. For that, you'll need to add something like the following block after that line above:
if ((currentTime > 0) && (newTime ==0)) {
// optionally turn off timer
fireZeroEvent ();
}
and provide the fireZeroEvent() function to do whatever you need to do.
I say optionally turn off the timer since you may want to leave it running so you can restart the countdown by just be setting time.text without have to recreate the timer.
For that reason, the fireZeroEvent() is only called on the transition from 1 to 0, not every time the timer fires after it reaches zero.
Related
I made a timer, but if I lock the screen, the timer stops ... how can I make it work when I block?
-(void)timeRun{
secondsCount = secondsCount - 1;
int minuts = secondsCount / 60;
int seconds = secondsCount - (minuts * 60);
NSString *timerOutput = [NSString stringWithFormat:#"%2d:%.2d", minuts, seconds];
TimerDisplay.text = timerOutput;
if (secondsCount == 0) {
[countdownTimer invalidate];
countdownTimer = nil;
AudioServicesPlaySystemSound(PlaySoundID);
}
}
Start the timer here
-(IBAction)Start:(id)sender{
secondsCount = perVrem;
countdownTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(timeRun) userInfo:nil repeats:YES];
}
Here I set the time 5 minutes
-(IBAction)fivemin:(id)sender{perVrem = 300;
TimerDisplay.text = [NSString stringWithFormat:#"05:00"];}
Difficult to answer without more context, but you may need
UIApplication.sharedApplication.idleTimerDisabled = NO;
or maybe you need to use
dispatch_after
or maybe you need to use the wall clock and just use your timer to update some UI.
Yours look like the latter, ie. use the wall clock and your timer just to update. If you count down 5 minutes accurately you'd have a start and end time and use a timer just to update the UI every now and again. So start becomes something like
-(IBAction)Start:(id)sender{
self.start = NSDate.date.timeIntervalSinceReferenceDate;
countdownTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(timeRun) userInfo:nil repeats:YES];
}
and timeRun something like
-(void)timeRun{
secondsCount = (x)( NSDate.date.timeIntervalSinceReferenceDate - self.start + 0.5 ); // Add a bit to get rounding right, depends on your types
...
where x will be e.g. int or long depending on secondsCount.
I m trying to write a loop to check that whenever audio player.currenttime increases by 2 seconds then it should execute update view method
- (void)myTimerMethod{
NSLog(#"myTimerMethod is Called");
myTimer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(checkPlaybackTime:)
userInfo:nil
repeats:YES];
}
- (void)checkPlaybackTime:(NSTimer *)theTimer
{
float seconds = audioplayer.currenttime;
NSLog(#"Cur: %f",audioPlayer.currentTime );
if (seconds = seconds + 2){
[self update view];
}
- (void)UpdateView{
if (index < [textArray count])
{
self.textView.text = [self.textArray objectAtIndex:index];
self.imageView.image = [self.imagesArray objectAtIndex:index];
index++;
}else{
index = 0;
}
}
what is the correct way to write if audio player.currenttimer increases by 2 seconds then do this.
NSLog for current time always shows 0.00. Why is that. It should increase as the audioplayer is playing.
Thanks for help.
What i understood from your given explanation that you want to increment the time-interval something like this
Timer calls after 0.55
Timer calls after 0.60
Timer calls after 0.65
Timer calls after 0.70
& so on.
If that is what you are looking to do. Then i think you can do this way that by changing repeats:YES to repeats:NO so that the timer doesn't repeat, and then in onTimer, just start a new timer with a longer interval.
You need a variable to hold your interval so that you can make it a bit longer each time through onTimer.
Also, you probably don't need to retain the timer anymore, as it will only fire once, and when it does, you'll get a new timer.
float gap = 0.50;
[NSTimer scheduledTimerWithTimeInterval:gap target:self selector:#selector(onTimer) userInfo:nil repeats:NO];
-(void) onTimer {
gap = gap + .05;
[NSTimer scheduledTimerWithTimeInterval:gap target:self selector:#selector(onTimer) userInfo:nil repeats:NO];
}
Hope this helps you
First, try using your float "seconds" in your NSLog rather than the current time.
NSLog(#"Cur: %f", seconds);
current time is not a float, it's an NSTimer object so you would have to use %# in your NSLog text so
NSLog(#"Cur: %#",audioPlayer.currentTime );
Should work as well.
Assuming your audioPlayer is set up correctly, if you're looking for when the timer is at 2 seconds, your if statement will be
if(seconds == 2){
[self update view];
}
if you're looking for each time the timer hits an even number, i.e. 2, 4, 6, etc. your if statement will be
if(seconds % 2 == 0){
[self update view];
}
The % in an if statement is the modulo sign: http://www.cprogramming.com/tutorial/modulus.html
Also, your current if statement is assigning rather than checking the seconds variable. To check it, you need == not =. However, your current if statement will never be true since you're checking a variable by itself + 2. To put this another way, if seconds equals 2, your if statement is asking if 2 == (2+2) or if it it is 4, it's asking if 2 == (4+2). This statement cannot validate as true.
Hope this helps!
Hello every time i try to record the date with CFAbsoluteTimeGetCurrent(); my app ignores the rest of the buttons, it's as if it takes over all memory and blocks all user input. I was wondering what i am doing wrong? I thought of making a function showtime() but i dont know how to pass values between functions from toggleRecording to showtime so that my method would work if this would even solve the problem. Below is my code:
- (IBAction)toggleRecording:(id)sender
{
// Start recording if there isn't a recording running. Stop recording if there is.
[[self recordButton] setEnabled:NO];
if (![[[self captureManager] recorder] isRecording]){
[[self captureManager] startRecording];
/* figure out a day to record for every half a second
while([[[self captureManager]recorder] isRecording]){
CFTimeInterval startTime = CFAbsoluteTimeGetCurrent();
NSLog(#" time is %i", startTime);
}
*/
}
else
[[self captureManager] stopRecording];
}
-(void)showtime:(id)sender{
while([[[self captureManager]recorder] isRecording]){
CFTimeInterval startTime = CFAbsoluteTimeGetCurrent();
NSLog(#" time is %f", startTime);
}
}
An application has to run the event loop to receive the events. While your own code is doing something else (here it's doing a "while" loop), events are queued and not delivered until your code returns.
Schematically, an application is doing something like:
while(1) {
event = _UIReceiveNextQueuedEvent();
_UIProcessEvent(event); // <- this calls -showTime:
}
If you want to record time while not blocking the loop, you will have to schedule an NSTimer every 0.5s and invalidate it as soon as recording is turned off.
Something like:
- (void)showTime:(id)sender
{
if ([[[self captureManager]recorder] isRecording]) {
[NSTimer scheduledTimerWithTimeInterval:0.5f target:self selector:#selector(timerFired:) userInfo:nil repeats:YES];
}
}
- (void)timerFired:(NSTimer *)timer
{
if ([[[self captureManager]recorder] isRecording]) {
CFTimeInterval startTime = CFAbsoluteTimeGetCurrent();
NSLog(#" time is %f", startTime);
} else {
[timer invalidate];
}
}
I have compiled the following code and there are no apparent runtime errors; however, the display freezes at 00:00:01 when I run it. It works if I only display the seconds attribute. Does anyone see an apparent oversight that I have missed in this code? I know there is a potential memory leak with the start button, but I will fix that eventually.
Thanks in advance.
#import "StopwatchViewController.h"
#implementation StopwatchViewController
- (IBAction)start{
//creates and fires timer every second
myTimer = [[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(showTime) userInfo:nil repeats:YES]retain];
}
- (IBAction)stop{
[myTimer invalidate];
myTimer = nil;
}
- (IBAction)reset{
[myTimer invalidate];
time.text = #"00:00:00";
}
(void)showTime{
int currentTime = [time.text intValue];
int new = currentTime +1;
int secs = new;
int mins = (secs/60) % 60;
int hours = (mins/60);
time.text = [NSString stringWithFormat:#"%.2d:%.2d:%.2d",hours, mins, secs];
}
You're getting 0 from
int currentTime = [time.text intValue];
because the string that's in text:
#"00:00:00"
can't be converted to an int, so every time the timer fires, you add 1 to 0 and get 1, which you then display. The math would be inaccurate anyways, because minutes and seconds are "base-60"* -- you'd need to do the reverse of the math you perform for separating hours/minutes/seconds, in order to get the total seconds again. You could just make currentTime an ivar, and keep the total number of seconds in it.
*That's not really what it's called; I'm sure there's a specific word for it.
- (IBAction)start{
currentTime = 0;
//creates and fires timer every second
myTimer = [[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(showTime) userInfo:nil repeats:YES]retain];
}
- (IBAction)stop{
[myTimer invalidate];
myTimer = nil;
}
- (IBAction)reset{
[myTimer invalidate];
time.text = #"00:00:00";
}
- (void)showTime{
currentTime++;
int secs = currentTime % 60;
int mins = (currentTime / 60) % 60;
int hour = (currentTime / 3600);
time.text = [NSString stringWithFormat:#"%.2d:%.2d:%.2d",hour, mins, secs];
}
i need a little help i have a method which gets value such as 50, it then assigns that value to trackDuration, so NSNumber *trackDuration = 50, i want the method to every second minus 1 from the value of trackDuration and update a label, the label being called duration.
Here's what i have so far;
- (void) countDown {
iTunesApplication *iTunes = [SBApplication applicationWithBundleIdentifier:#"com.apple.iTunes"];
NSNumber *trackDuration = [NSNumber numberWithDouble:[[iTunes currentTrack] duration]];
while (trackDuration > 0) {
trackDuration - 1;
int inputSeconds = [trackDuration intValue];
int hours = inputSeconds / 3600;
int minutes = ( inputSeconds - hours * 3600 ) / 60;
int seconds = inputSeconds - hours * 3600 - minutes * 60;
NSString *trackDurationString = [NSString stringWithFormat:#"%.2d:%.2d:%.2d", hours, minutes, seconds];
[duration setStringValue:trackDurationString];
sleep(1);
}}
Any help would be much appreciated, thanks in advanced, Sami.
This will block the main thread, and you are not assigning the value trackDuration, so it will always stay 50
trackDuration -1;
Should be:
trackDuration--; // or trackDuration -= 1;
Also I would do it like this:
- (void)startCountDown
{
[NSTimer scheduledTimerWithInterval:1.0f target:self selector:#selector(timerHit:) userInfo:nil repeats:YES];
}
- (void)timerHit:(NSTimer *)p_timer
{
if( trackDuration <= 1 && [p_timer isValid] )
[p_timer invalidate];
// track duration is an instance variable
trackDuration--;
// update LABEL
}
iOS 2.x or higher is required for NSTimer
Having this method run in a loop will make your app go unresponsive for the whole time it's running — you won't even see any UI updates. Instead, you should use an NSTimer with an interval of one second, and update the elapsed time when the timer fires.