How to start a timer from zero in iOS - ios

I have a button on which i have placed a UITapGestureRecognizer. When i tap on that button, i call a method that starts the time.
My question is, i am able to get the timer string on a label. But the timer starts from current date-time, and i want to start the timer always from zero(like a countdown timer). Here below is my code for timer.
-(IBAction)micPressed{
if (gestureRecognizer.state==UIGestureRecognizerStateBegan) {
gestureRecognizer.view.alpha=0.2f;
[label setHidden:NO];
if (!_timer) {
_timer = [NSTimer scheduledTimerWithTimeInterval:0.1f
target:self
selector:#selector(_timerFired:)
userInfo:nil
repeats:YES];
}
}
else{
[label setHidden:YES];
gestureRecognizer.view.alpha=10.2f;
if ([_timer isValid]) {
[_timer invalidate];
}
_timer = nil;
}
}
- (void)_timerFired:(NSTimer *)timer {
NSDateFormatter *dateformatter=[[NSDateFormatter alloc]init];
[dateformatter setDateFormat:#"mm:ss:SSS"];
NSString *dateInStringFormated=[dateformatter stringFromDate:[NSDate dateWithTimeIntervalSinceNow:0]];
NSLog(#"%#",dateInStringFormated);
[label setText:dateInStringFormated];
}
Please can anyone suggest me the solution. Any help is appreciated.

Your code should be like,
NSDateFormatter *dateformatter=[[NSDateFormatter alloc]init];
[dateformatter setDateFormat:#"mm:ss:SSS"];
NSString *dateInStringFormated=[dateformatter stringFromDate:[dateformatter dateFromString:#"00:00:000"]];
NSLog(#"test : %#",dateInStringFormated);
I have just chage [NSDate dateWithTimeIntervalSinceNow:0] with [dateformatter dateFromString:#"00:00:000"].
It will start with zero always.
Update :
I think you want something like timer that update minutes,seconds and milliseconds as i understand your question now. You can achieve it something like,
Schedule timer like,
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:#selector(updateTimer) userInfo:nil repeats:YES];
Now your updateTimer should be like,
-(void)updateTimer{
static double counter = 0;
static int counter2 = 0;
int seconds = (int)counter % 60;
int minutes = ((int)counter / 60) % 60;
NSLog(#"%02d:%02d:%03d",minutes,seconds,counter2); // This should be your labels text that updating continuously
counter = counter + 0.01;
counter2++;
if (counter2 == 100) {
counter2 = 0;
}
}
Hope this will help :)

The problem is you are starting your timer from current time itself. To make a like countdown timer. You need to do the following:
Take an int named Counter and intialize it from 0
Fire your NSTimer and at that time increase the counter
Display the counter value in the UILabel text.
Once your NSTimer stops, again make it to 0.
That's it! This is how you can achieve the desired result.
Code:
int counter = 0;
- (void)_timerFired:(NSTimer *)timer {
counter++;
}
Once NSTimer is invalidate again make it to counter = 0

Remember the time when you have started the timer:
_startDate = [NSDate date];
_Timer = ...
Then use the time interval since the start date in your _timerFired method:
NSDateComponentsFormatter *formatter = [[NSDateComponentsFormatter alloc] init];
NSString *dateInStringFormatted = [formatter stringFromTimeInterval:[[NSDate date] timeIntervalSinceDate:_startDate]];

Related

How to fix "exc_bad_instruction (code=exc_i386_invop subcode=0x0)"

I want to make a timer in my app, but i find a problem like this:
My code run very well at viewController which contain the code below, but after i dismiss this viewController a few seconds, Xcode will report an erro: exc_bad_instruction (code=exc_i386_invop subcode=0x0
If i didn't use dispatch_suspend(self.timer) and dispatch_resume(self.timer), everything will be ok
otherwise, I can see the error will happen when Xcode deal with [viewController .cxx_destruct]
so, anyone can tell me how to fix it?
Thank you
Here is my code,
- (void)timeButtonClick:(UIButton *)button{
if (self.isTiming == YES){
self.isTiming = NO;
self.executeTime = [self.timeButton currentTitle];
dispatch_suspend(self.timer);
}else if (self.isTiming == NO){
self.isTiming = YES;
self.createDate = [NSDate date];
dispatch_resume(self.timer);
}
}
- (dispatch_object_t)timer{
if (_timer == nil) {
dispatch_queue_t timerQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, timerQueue);
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
__weak typeof (self)weakSelf = self;
dispatch_source_set_event_handler(timer, ^{
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = #"HH:mm:ss";
NSCalendar *calendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian];
NSCalendarUnit unit = NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
NSDate *currentDate = [NSDate date];
NSDateComponents *currentCmps = [calendar components:unit fromDate:weakSelf.createDate toDate:currentDate options:NSCalendarWrapComponents];
NSDate *executeTime = [dateFormatter dateFromString:weakSelf.executeTime];
NSDateComponents *executeCmps = [calendar components:unit fromDate:executeTime];
NSString *newExecuteTime = [NSString stringWithFormat:#"%02ld:%02ld:%02ld", executeCmps.hour + currentCmps.hour, executeCmps.minute + currentCmps.minute, executeCmps.second + currentCmps.second];
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf.timeButton setTitle:newExecuteTime forState:UIControlStateNormal];
});
});
_timer = timer;
}
return _timer;
}
Move your timer to another place like AppDelegate, you are getting this error because you are dispatching the timer to another thread, then when the VC is dismissed the timer wants to set the title to timeButton which wa salready destroyed when the VC was dismissed.
You could also try to make a strong weakself, but I really suggest you to move the timer code to another class.

Refreshing data from server using NSTimer

i want to refresh the data from the server ,but that refreshing time-> i want to get that from the user and pass to the timer ,how can i do this i know to give the value like,
self.timerCounter =[NSTimer scheduledTimerWithTimeInterval:300.0
target:self selector:#selector(getGraphData) userInfo:nil repeats:YES];
i also tried using protocols and delegates like ,
self.timerCounter =[NSTimer scheduledTimerWithTimeInterval:strTime
target:self selector:#selector(getGraphData) userInfo:nil repeats:YES];
but i got error like
Sending NSString _strong to parameter of incompatible type
NSTimerInterval
now ,i want to get that from the user in the textfield ,please help me to do this
I think there is the problem in converting strTime to NSTimeInterval.
self.timerCounter =[NSTimer scheduledTimerWithTimeInterval:[strTime doubleValue] target:self selector:#selector(getGraphData) userInfo:nil repeats:YES];
Try this, This should work if there is conversion problem..
Convert textfield.text to NSTimeInterval
Try like,
let strTime : NSTimeInterval = NSTimeInterval(textfield.text)!
You are using NSString instead of a NSTimeInterval type data. You should be able to resolve this by converting your txtTime or strTime to a double value.
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *url = [defaults objectForKey:#"server_url"];
NSString *txtTime = [defaults objectForKey:#"refresh_time"];
if (txtTime != nil) {
NSTimeInterval timeInterval = [txtTime doubleValue];
self.timerCounter = [NSTimer scheduledTimerWithTimeInterval:timeInterval target:self selector:#selector(getGraphData) userInfo:nil repeats:true];
}

How to Create a count up timer in iOS

I have this code:
NSDate *now = [NSDate date];
static NSDateFormatter *dateFormatter;
if (!dateFormatter) {
dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = #"h:mm:ss";
}
recordStatusLabel.text = [dateFormatter stringFromDate:now];
NSLog(#"Time now: %#", [dateFormatter stringFromDate:now]);
that counts the current time. How can i change it to start in this format?
00:00:00 (hours:minutes:seconds)
from a NSString variable:
Example: i got this value for my variable
NSString * time = #"02:16:23";
then the counter will continue the count to:
02:16:24
.
.
.
02:20:13
Create an instance of NSTimer class and set time for event fire 1 second with repeat option YES. In the event handling update your label with current time. When your functionality is complete, invalidate the timer to stop firing events.
Here is the code to create instance of NSTimer class:
NSTimer *countUpTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self
selector:#selector(countUpTimerFired:) userInfo:nil repeats:YES];
Here is the method for event handling:
- (void)countUpTimerFired:(id)sender {
dispatch_async(dispatch_get_main_queue(), ^{
recordStatusLabel.text = [dateFormatter stringFromDate:[NSDate date]];
});
}
Keep of dateFormatter and countUpTimer as class variables.
This is the simple approach to achieve your required functionality as you are starting your time from current device time; So you won't be requiring extra efforts to get value from label, incrementing the value and then converting back to string.
EDIT:
If you want to start the counter from anyother time value or from a string, you can keep a integer variable to keep the value of time in seconds. Then increment the value when timer event gets called (every second) and then converting that integer to time string.
Here's the code for initial value:
NSString *timeString = recordStatusLabel.text; //contains a string in time format like #"2:16:23" or #"00:00:00" or current time or any other value.
NSArray *timeComponents = [timeString componentsSeparatedByString:#":"];
int timeInSeconds = [timeComponents[0] intValue]*3600 + [timeComponents[1] intValue]*60 + [timeComponents[2] intValue];
in the event handling of timer:
- (void)countUpTimerFired:(id)sender {
timeInSeconds++;
int hours = timeInSeconds/3600;
int minutes = (timeInSeconds%3600)/60;
int seconds = timeInSeconds%60;
dispatch_async(dispatch_get_main_queue(), ^{
[recordStatusLabel setText:[NSString stringWithFormat:#"%d:%02d:%02d", hours, minutes, seconds]];
});
}
Since you are dealing with a timer which the fastest value is the second, then to achieve performance you just fire a timer which repeats every second.
Declare your instance variables
#implementation Yourclass {
NSDate *startDate;
NSTimer *yourTimer;
NSString *myTime;
}
When you click a button to start timer
-(IBAction)startTimer:(id)sender {
startDate = [NSDate date];
yourTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(timeHandler:) userInfo:nil repeats:YES];
[yourTimer fire];
}
Implement your method which is the handler method of timer
-(void)timeHandler:(NSTimer *)myTimer {
//Difference between dates in seconds
NSTimeInterval elapsedTime = [startDate timeIntervalSinceNow];
//Divide by 3600 to get the hours
NSInteger hours = elapsedTime/3600;
//Divide by 60 to get the minutes
NSInteger minutes = elapsedTime/60;
NSInteger seconds = elapsedTime;
myTime = [NSString stringWithFormat:#"%i:%i:%i",hours, minutes, seconds];
// update the label
recordStatusLabel.text = myTime;
}

iOS uilabel text cross view

I am doing a countdown apps with storyboard and navigation controller with 2 view controller
"A" controller is with UILABEL showing how many days
and "B" Controller is a date picker with button below is the code from "B" controller
- (IBAction)doneSetting:(id)sender
{
//Remove the time component from the datePicker. We care only about the date
NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];
NSUInteger preservedComponents = (NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit);
self.datePicker.date = [calendar dateFromComponents:[calendar components:preservedComponents fromDate:self.datePicker.date]];
//Set up a timer that calls the updateTime method every second to update the label
NSTimer *timer;
timer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(updateTime)
userInfo:nil
repeats:YES];
}
-(void)updateTime
{
//Get the time left until the specified date
NSInteger ti = ((NSInteger)[self.datePicker.date timeIntervalSinceNow]);
NSInteger days = (ti / 86400);
//Update the lable with the remaining time
self.countdownLabel.text = [NSString stringWithFormat:#"%02i days", days];
}
how do I get the countdownlabel.text to appear on "A" Controller?
Thanks in advance
Try this:
//======= in controller B =====
Declare property in Controller "B" in .h file:
#property (nonatomic, copy) void (^LabelTextUpdated)(NSString *textValue);
and in .m of B in your source code:
-(void)updateTime
{
//Get the time left until the specified date
NSInteger ti = ((NSInteger)[self.datePicker.date timeIntervalSinceNow]);
NSInteger days = (ti / 86400);
//Update the lable with the remaining time
self.countdownLabel.text = [NSString stringWithFormat:#"%02i days", days];
if (_LabelTextUpdated) {
_LabelTextUpdated(#"Value");
}
}
//========== And in controller "A" ===========
from where you are pushing controller "B" write this:
B *object_B = YOUR_OBJECT_OF_B;
[object_B setLabelTextUpdated:^(NSString *textValue) {
//Here you will receive updated text
NSLog(#"Your Text is %#", textValue);
}];
//Push your B controller.

Format NSTimeInterval as Minutes:Seconds:milliseconds

Can anyone please tell me how to display milliseconds in this piece of code?
-(void)updateViewForPlayerInfo:(AVAudioPlayer*)p {
countdownTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(updateTimeLeft)userInfo:p repeats:YES];
}
- (void)updateTimeLeft {
NSTimeInterval timeLeft = player.duration - player.currentTime;
int min=timeLeft / 60;
int sec=lroundf(timeLeft) % 60;
durationLabel.text = [NSString stringWithFormat:#"-%02d:%02d",min,sec,nil];
}
[NSTimer scheduledTimerWithTimeInterval:0.0167 target:self selector:#selector(updateTimer) userInfo:nil repeats:YES];
-(void)updateTimer {
countDownTotalTimer++;
TotalTime.text=[self timeFormatted:countDownTotalTimer];
}
- (NSString *)timeFormatted:(int)milli
{
int millisec = ((milli) % 60)+39;
int sec = (milli / 60) % 60;
int min = milli / 3600;
return [NSString stringWithFormat:#"%02d:%02d:%02d",min, sec, millisec];
}
If any wants milliseconds to max 60 than edit this line
int millisec = ((milli) % 60)+39;
to
int millisec = ((milli) % 60);
I don't understand. Don't you just have to create a new variable for the milliseconds?
NSInteger milliseconds = (sec * 1000);
durationLabel.text = [NSString stringWithFormat:#"-%02d:%02d.%04d",min,sec, milliseconds, nil];
I think this is the simplest solution:
durationLabel.text = [NSString stringWithFormat:#"-%02d:%06.3f",
(int)(timeLeft / 60), fmod(timeLeft, 60)];
That formats the time as MM:SS.sss. If you really want it as MM:SS:sss (which I don't recommend), you can do this:
durationLabel.text = [NSString stringWithFormat:#"-%02d:%02d:%03.0f",
(int)(timeLeft / 60), (int)fmod(timeLeft, 60), 1000*fmod(timeLeft, 1)];
Note that stringWithFormat: does not require nil at the end of its argument list.

Resources