How to set time count down in iPhone? - iphone

I want to set time count down like start with 60sec then elapsed 59,58,57 etc... this elapsed time show in bottom of the screen, How to set this?
Please help me
Thanks in Advance

You can use like:
Declare a NSTimer object on the #interface like NSTimer *aTimer;
-(void)viewDidLoad
{
aTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(elapsedTime) userInfo:nil repeats:YES];
}
-(void)elapsedTime
{
static int i = 60;
label.text = [NSString stringWithFormat:#"%d",i];
i--;
if(i<0)
{
[aTimer invalidate];
aTimer = nil;
}
}
Here label is a IBOutlet UILabel, that is set to interface.

You can do this with NSTimer see my example -
Declared
NSTimer *timer;
int count;
Globally in your ViewController.h class
Then you can start your count down in viewDidLoad: method.
- (void)viewDidLoad
{
//label is your **UILabel**
label.text = #"60";
count = 59;
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(countDown) userInfo:nil repeats:YES];
}
-(void)countDown
{
if(count > 0)
{
label.text = [[NSNumber numberWithInt:count] stringValue];
count --;
}
else
{
[timer invalidate];
}
}

Related

How can I detach a thread without calling the selector, or at least make a work-around?

So I have a view controller with a timer. It has one button. When the view loads for the very first time, the button should say "start."
When it is tapped, "start"->"pause".
Another tap, "pause"->"resume".
Another tap, "resume"->"pause".
Since I want the timer to be accurate, I detached it from the main thread (I think I chose the right method, I would appreciate some clarification). But it seems like detaching it from the thread actually calls the method...which makes the button start with "pause" instead of start. How do I fix this?
By the way, default value (loads with) for testTask.showButtonValue is 1.
- (void)viewDidLoad {
[super viewDidLoad];
[NSThread detachNewThreadSelector:#selector(startTimer:) toTarget:self withObject:nil];
if (testTask.showButtonValue == 1) {
[startButton setTitle:#"Start" forState:UIControlStateNormal];
} else if (testTask.showButtonValue == 2) {
[startButton setTitle:#"Pause" forState:UIControlStateNormal];
} else if (testTask.showButtonValue == 3){
[startButton setTitle:#"Resume" forState:UIControlStateNormal];
}
}
-(IBAction)startTimer:(id)sender{
if (testTask.showButtonValue == 1) {
[startButton setTitle:#"Pause" forState:UIControlStateNormal];
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(timerAction:) userInfo:nil repeats:YES];
testTask.showButtonValue = 2;
} else if (testTask.showButtonValue == 2) {
[startButton setTitle:#"Resume" forState:UIControlStateNormal];
[timer invalidate];
timer = nil;
testTask.showButtonValue = 3;
} else if (testTask.showButtonValue == 3){
[startButton setTitle:#"Pause" forState:UIControlStateNormal];
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(timerAction:) userInfo:nil repeats:YES];
testTask.showButtonValue = 2;
}
}
-(void)timerAction:(NSTimer *)t
{
if(testTask.timeInterval == 0)
{
if (self.timer)
{
[self timerExpired];
[self.timer invalidate];
self.timer = nil;
}
}
else
{
testTask.timeInterval--;
}
NSUInteger seconds = (NSUInteger)round(testTask.timeInterval);
NSString *string = [NSString stringWithFormat:#"%02u:%02u:%02u",
seconds / 3600, (seconds / 60) % 60, seconds % 60];
timerLabel.text = string;
NSLog(#"%f", testTask.timeInterval);
}
I suggest going about this in a different way:
#interface SNDViewController ()
#property (weak, nonatomic) IBOutlet UIButton *startButton;
#property (weak, nonatomic) IBOutlet UILabel *timerLabel;
#property (nonatomic, strong) NSTimer *timer;
#property (nonatomic, assign) NSTimeInterval accumulativeTime;
#property (nonatomic, assign) NSTimeInterval currentReferenceTime;
#end
#implementation SNDViewController
EDIT: when the view loads, initialise self.accumulativeTime and update the timer label. The initialisation of accumulativeTime variable should really be done in the appropriate init* method, e.g. initWithNibName:bundle:. It is at this point that you would read the timer value from core data.
- (void)viewDidLoad
{
[super viewDidLoad];
self.accumulativeTime = 300;
[self updateTimerLabelWithTotalTime:self.accumulativeTime];
}
- (IBAction)changeTimerState:(UIButton *)sender
{
if (self.timer == nil) {
self.currentReferenceTime = [NSDate timeIntervalSinceReferenceDate];
[self.timer invalidate];
self.timer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:#selector(updateTimer:) userInfo:nil repeats:YES];
} else {
//Pause the timer and track accumulative time.
NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
[self.timer invalidate];
self.timer = nil;
NSTimeInterval timeSinceCurrentReference = now - self.currentReferenceTime;
EDIT: subtract timeSinceCurrentReference from accumalitiveTime, because this is a countdown timer. Also added a comment for saving to core data if necessary.
self.accumulativeTime -= timeSinceCurrentReference;
[self updateTimerLabelWithTotalTime:self.accumulativeTime];
//Optionally save self.accumulativeTime to core data for future use.
}
NSString *buttonTitle = (self.timer != nil) ? #"Pause" : #"Resume";
[self.startButton setTitle:buttonTitle forState:UIControlStateNormal];
}
You don't need to store any unnecessary state, such as the showButtonValue variable. Instead you can base your decision of whether to pause or resume on whether or not self.timer == nil. If there is no timer running, then grab the current reference time and start a new timer. The timer is scheduled to fire every 0.01 seconds, which will hopefully make it accurate to 0.1 seconds. You never need to change the button's title to "Start". It is either "Pause" or "Resume".
When the timer is paused by the user, we dispose of self.timer and update the timer label with the most accurate time.
- (void)updateTimer:(id)sender
{
NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
NSTimeInterval timeSinceCurrentReference = now - self.currentReferenceTime;
EDIT: subtract timeSinceCurrentReference from self.accumulativeTime to get the totalTime (i.e. totalTime decreases as time goes by).
NSTimeInterval totalTime = self.accumulativeTime - timeSinceCurrentReference;
if (totalTime <= 0) {
totalTime = 0;
[self.timer invalidate];
self.timer = nil;
//What to do when we reach zero? For example, we could reset timer to 5 minutes:
self.accumulativeTime = 300;
totalTime = self.accumulativeTime;
[self.startButton setTitle:#"Start" forState:UIControlStateNormal];
}
[self updateTimerLabelWithTotalTime:totalTime];
}
Each time the timer is fired, we get the total time by finding the difference between now and self.currentReferenceTime and add it to self.accumulativeTime.
- (void)updateTimerLabelWithTotalTime:(NSTimeInterval)totalTime
{
NSInteger hours = totalTime / 3600;
NSInteger minutes = totalTime / 60;
NSInteger seconds = totalTime;
NSInteger fractions = totalTime * 10;
self.timerLabel.text = [NSString stringWithFormat:#"%02u:%02u:%02u.%01u", hours, minutes % 60, seconds % 60, fractions % 10];
}
#end
The method - (IBAction)changeTimerState:(UIButton *)sender is called by the UIButton on the "Touch Up Inside" event (UIControlEventTouchUpInside).
You don't need to do anything in viewDidLoad.
Also, and importantly, this is all done on the main thread. If anything gets in the way of the main thread updating the timer label, then the text visible to the user may be inaccurate, but when it is updated, you can be sure that it will be accurate again. It depends on what else your app is doing. But since all UI updates must be done on the main thread there is really no avoiding this.
Hope this helps. Let me know if anything is unclear.
(Xcode project available here: https://github.com/sdods3782/TVTTableViewTest)
Calling detachNewThreadSelector will create a new thread and perform the selector mentioned, immediately afer the call.
For fixing your issue change your methods like:
- (void)viewDidLoad
{
[super viewDidLoad];
[NSThread detachNewThreadSelector:#selector(startTimer:) toTarget:self withObject:nil];
}
-(IBAction)startTimer:(id)sender
{
if (testTask.showButtonValue == 1) {
[startButton setTitle:#"Start" forState:UIControlStateNormal];
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(timerAction:) userInfo:nil repeats:YES];
testTask.showButtonValue = 3;
} else if (testTask.showButtonValue == 2) {
[startButton setTitle:#"Resume" forState:UIControlStateNormal];
[timer invalidate];
timer = nil;
testTask.showButtonValue = 3;
} else if (testTask.showButtonValue == 3){
[startButton setTitle:#"Pause" forState:UIControlStateNormal];
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(timerAction:) userInfo:nil repeats:YES];
testTask.showButtonValue = 2;
}
}

Resetting Timer issues IOS

I'm working on a buzzer app for IOS. When you click the buzzer, it buzzes, 30 seconds pops up, and counts down until after 1 and then buzzes and disappears. If, during the course of the 30-second countdown, someone wants to reset the buzzer (so that the timer goes off and disappears), they will just click the buzzer again.
I have three questions:
1. How do you start the app with the UILabel invisible and then shows up upon the first click?
2. How do you reset the buzzer by clicking it during the 30 second countdown?
3. Will reseting the buzzer fix the problem of the timer going down extremely quick when clicked multiple times?
viewcontrol.h
#import <UIKit/UIKit.h>
#import <AudioToolbox/AudioToolbox.h>
#interface ViewController : UIViewController {
IBOutlet UILabel *seconds;
NSTimer *timer;
int MainInt;
SystemSoundID buzzer;
}
- (IBAction)start:(id)sender;
- (void)countdown;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
-(IBAction)start:(id)sender {
seconds.hidden = NO;
MainInt = 30;
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(countdown) userInfo:nil repeats:YES];
AudioServicesPlaySystemSound(buzzer);
}
-(void)countdown {
MainInt -= 1;
seconds.text = [NSString stringWithFormat:#"%i", MainInt];
if (MainInt < 1) {
[timer invalidate];
timer = nil;
seconds.hidden = YES;
AudioServicesPlaySystemSound(buzzer);
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSURL *buttonURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"Buzz" ofType:#"wav"]];
AudioServicesCreateSystemSoundID((__bridge CFURLRef)buttonURL, &buzzer);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
1) hiding the label on startup
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//hide the label initially
[seconds setHidden:YES];
/// other code
then call [seconds setHidden:NO]; in start method
2) reset buzzer
-(IBAction)start:(id)sender {
seconds.hidden = NO;
MainInt = 30;
if(timer != nil)
{
//timer exist..stop previous timer first.
[timer invalidate];
}
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(countdown) userInfo:nil repeats:YES];
AudioServicesPlaySystemSound(buzzer);
}
1) For the label becoming visible on a delay, initialize the label (in code or in IB) with seconds.alpha = 0.0. Then to make it visible...
NSTimeInterval delayUntilLabelIsVisible = 3.0; // 3 seconds
[UIView animateWithDuration:0.3
delay:delayUntilLabelIsVisible
options:UIViewAnimationCurveEaseIn
animations:^{seconds.alpha = 1.0;}
completion:^(BOOL finished) {}];
2,3) Your second and third questions can be solved with a line of code in the start method...
-(IBAction)start:(id)sender {
seconds.hidden = NO;
MainInt = 30;
// cancel the old timer before creating a new one
// (otherwise many timers will run at once, calling the buzzer method too often)
[timer invalidate];
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(countdown) userInfo:nil repeats:YES];
AudioServicesPlaySystemSound(buzzer);
}

Images not getting changed with NSTimer

This is my code
- (void)updateCounterImage:(NSTimer *)theTimer
{
static int count = 0;
count += 1;
int crb = 6 - count;
UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:#"ipad_game_timer_digit-%d.png", crb]];
if ( count == 6)
[timer release];
[countTime setImage:image];
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
[super viewDidLoad];
correctLevel.hidden = YES;
incorrectLevel.hidden = YES;
incorrectAnswer.hidden = YES;
correctAnswer.hidden = YES;
timer = [NSTimer scheduledTimerWithTimeInterval:1.0f
target:self
selector:#selector(updateCounterImage:)
userInfo:nil
repeats:NO];
}
#import <UIKit/UIKit.h>
#interface GameController : UIViewController
{
IBOutlet UIImageView *countTime;
NSTimer *timer;
}
#end
The problem is my imageView is not changing its image for countime.
You have set repeats to NO in the scheduledTimerWithTimeInterval which means the timer will only tick once.
You should write
timer = [NSTimer scheduledTimerWithTimeInterval:1.0f
target:self
selector:#selector(updateCounterImage:)
userInfo:nil
repeats:YES];

How to change the label text dynamically

I want to make a "downloading" uilabel whose label text will change dynamically when I call the method "updating":
self.checkingArray = [NSArray arrayWithObjects:#"download", #"download.", #"download..", #"download...",
nil];
- (void) updating
{
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:#selector(changeText) userInfo:nil repeats:YES];
}
- (void) changeText
{
checkLabel.text = [self.checkingArray objectAtIndex:curCheckingState];
self.curCheckingState++;
if (self.curCheckingState >= 4) {
self.curCheckingState = 0;
}
But the label text stay with the text "download...", I want to know how to achieve my purpose?
Implement this:
- (void) updating
{
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(changeText) userInfo:nil repeats:YES];
}
- (void) changeText
{
static unsigned char state = 0;
checkLabel.text = [self.checkingArray objectAtIndex:state];
if(state < 3) state++;
else state = 0;
}
Do this:
self.checkingArray = [NSArray arrayWithObjects:#"download", #"download.", #"download..", #"download...",
nil];
self.curCheckingState = 0;
- (void) updating
{
//change timer time interval if needed
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(changeText) userInfo:nil repeats:YES];
}
- (void) changeText
{
checkLabel.text = [self.checkingArray objectAtIndex:self.curCheckingState];
if (self.curCheckingState == 3) //depending on [array count]-1
{
self.curCheckingState = 0;
}
else
{
self.curCheckingState++;
}
}

Unable to get NSTimer to work

Using NSTimer for my application in which I have to show countdown timer with initial timing equal to 100sec. It shows 99,then 98..96..94..92...86 and so on. But I want each sec to show up. Here is my code....
-(void)updateTimerLabel{
if (timeRemaining>0 ) {
timeRemaining=timeRemaining-1.0;
timerLabel.text=[NSString stringWithFormat:#"%.0f", timeRemaining];
countdownTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateTimerLabel) userInfo:nil repeats:YES];
}
}
Try following code
int i =100;
-(void)viewDidLoad
{
[super viewDidLoad];
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(theActionMethod) userInfo:nil repeats:YES];
}
-(void)theActionMethod
{
if(i > 0)
{
NSString *str = [NSString stringWithFormat:#"%d",i];
lbl.text = str;
}
i--;
}
You are actually re-creating the timer every time your method gets called.
You should try leaving that outside and retaining it until you're finished with it.
#interface SomeClass
NSTimer * aTimer;
#end
#implementation
- (void)createTimer {
aTimer = [[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateTimerLabel) userInfo:nil repeats:YES] retain];
}
- (void)updateTimerLabel {
// do timer updates here
// call [aTimer release]
// and [aTimer invalidate]
// aTimer = nil;
// when you're done
}
#end
you have call updateTimerLabel outside the method.
ex:
-(void)viewDidLoad{timeRemaining=100.0;[self updateTimerLabel];countdownTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateTimerLabel) userInfo:nil repeats:YES];}
-(void)updateTimerLabel
{if (timeRemaining>0 )
{timeRemaining=timeRemaining-1.0;NSLog(#"%#",[NSString stringWithFormat:#"%.0f",timeRemaining]);}}