I discovered an issue with my sample project. I simply create a scheduledTimer that "animate" a label and then, when I reached the result I want, I invalidate the timer and I set an another one, this time as a "clock".
This is the code I use
//
// ViewController.m
//
//
//
//
//
#import "ViewController.h"
#define ANIMATION_INTERVAL 0.07 // in secondi
#define ANIMATION_DURATION 1 // in secondi
#interface ViewController ()
{
int contatore;
NSString *hour;
NSString *minute;
NSString *second;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
contatore = 0;
[self startTimeAnimation];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)startTimeAnimation
{
NSTimer * animationTimer = [NSTimer scheduledTimerWithTimeInterval:ANIMATION_INTERVAL target:self selector:#selector(timeout:) userInfo:nil repeats:YES];
}
-(void)timeout: (NSTimer *)timer
{
// Simulate of the Timer Duration with a counter
if (contatore < ceilf(ANIMATION_DURATION/ANIMATION_INTERVAL))
{
// Proceed with animation
contatore++;
int tempHour = arc4random_uniform(24);
int tempMinute = arc4random_uniform(60);
int tempSecond = arc4random_uniform(60);
if (tempHour < 10)
{
hour = [NSString stringWithFormat:#"0%d", tempHour];
}
else
{
hour = [NSString stringWithFormat:#"%d", tempHour];
}
if (tempMinute < 10)
{
minute = [NSString stringWithFormat:#"0%d", tempMinute];
}
else
{
minute = [NSString stringWithFormat:#"%d", tempMinute];
}
if (tempSecond < 10)
{
second = [NSString stringWithFormat:#"0%d", tempSecond];
}
else
{
second = [NSString stringWithFormat:#"%d", tempSecond];
}
_orarioLbl.text = [NSString stringWithFormat:#"%#:%#:%#", hour, minute, second];
}
else
{
// Stops animation
[timer invalidate];
[timer release];
contatore = 0;
[self setActualTime];
// Starts clock
NSTimer *clockTimer = [NSTimer timerWithTimeInterval:.5f target:self selector:#selector(updateClock) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:clockTimer forMode:NSRunLoopCommonModes];
}
}
-(void)updateClock
{
[self setActualTime];
}
-(void)setActualTime
{
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"HH"];
hour = [dateFormatter stringFromDate:[NSDate date]];
[dateFormatter setDateFormat:#"mm"];
minute = [dateFormatter stringFromDate:[NSDate date]];
[dateFormatter setDateFormat:#"ss"];
second = [dateFormatter stringFromDate:[NSDate date]];
_orarioLbl.text = [NSString stringWithFormat:#"%#:%#:%#", hour, minute, second];
[dateFormatter release];
}
#end
Since I start the "clock", memory still stays on 19/20 MB with constant persistent allocation. When the timer updates the minute value, persistent allocations increase as you can see in the gif! How is it possible? However, also 19MB of memory is too much for a simple clock, isn't it?
Profiling on Instruments, the new allocations are all about CoreGraphics!
EDIT I tested it on another device and the persistent allocations decreased. I don't know why, but I solved in this way. Thanks
NSTimer retains its target and that may lead to a retain cycle. Grab a weak reference to self and set that as the target:
__weak typeof(self) weakSelf = self;
NSTimer * animationTimer = [NSTimer scheduledTimerWithTimeInterval:ANIMATION_INTERVAL target:weakSelf selector:#selector(timeout:) userInfo:nil repeats:YES];
and
__weak typeof(self) weakSelf = self;
NSTimer *clockTimer = [NSTimer timerWithTimeInterval:.5f target:weakSelf selector:#selector(updateClock) userInfo:nil repeats:YES];
May I also recommend you create a property for the dateFormatter, as NSDateFormatters are expensive to create. And why are you releasing the dateFormatter? Are you not using ARC?
Related
I am creating a game application in which I need to set timer of 2 minutes throughout the app screens in objective c.
I am creating it in viewDidLoad but it is creating a new instance every-time the view loads.
Here is the code which I am using :
#interface SomeViewController ()
{
int timerCounter;
NSTimer *timer;
}
#property (strong, nonatomic) IBOutlet UILabel *timerLbl;
#end
#implementation SomeViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self startCountdown];
}
- (void)startCountdown
{
timer = [NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:#selector(countdownTimer:)
userInfo:nil
repeats:YES];
}
- (void)countdownTimer:(NSTimer *)timer
{
timerCounter--;
int minutes = timerCounter / 60;
int seconds = timerCounter % 60;
NSString *string = [NSString stringWithFormat:#"%02d", minutes];
NSString *string2 = [NSString stringWithFormat:#"%02d", seconds];
NSString *timeTotal = [string stringByAppendingString:#":"];
NSString *timeTotal2 = [timeTotal stringByAppendingString:string2];
_timerLbl.text = timeTotal2;
if (timerCounter <= 0) {
[timer invalidate];
}
}
You need to invalidate it whenever the VC deallocates
- (void)dealloc {
[timer invalidate];
}
//
The second VC may look like this
#import "ggViewController.h"
NSInteger timerCounter = 120; // declared global to hold the value
#interface ggViewController ()
{
NSTimer*timer;
}
#end
#implementation ggViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
// instead of using selector use this inline callback
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 repeats:true block:^(NSTimer * timer) {
timerCounter--;
int minutes = timerCounter / 60;
int seconds = timerCounter % 60;
NSString *string = [NSString stringWithFormat:#"%02d", minutes];
NSString *string2 = [NSString stringWithFormat:#"%02d", seconds];
NSString *timeTotal = [string stringByAppendingString:#":"];
NSString *timeTotal2 = [timeTotal stringByAppendingString:string2];
_timerLbl.text = timeTotal2;
if (timerCounter <= 0) {
[timer invalidate];
}
}];
}
-(void)viewDidDisappear:(BOOL)animated{
[super viewDidDisappear:animated];
[timer invalidate];
}
- (IBAction)gg:(id)sender {
[self dismissViewControllerAnimated:true completion:nil];
}
#end
I m using timer on circular progress bar and taken NSDate property in interface (tested also taking in viewWillAppear) but when viewController loads it show starting from 27 seconds remain, while i have set its value to 30 seconds.
My scenario is, a user has a question and optional answers and he/she has some time suppose 30 seconds when he/she click start button than another screen opens after this screen loads time start should be from 30 seconds.
#interface TestViewController ()
{
NSTimeInterval totalCountdownInterval;
NSDate* startDate;
}
}
-(void)viewWillAppear:(BOOL)animated{
[self startTimer];
totalCountdownInterval = 30.0;
startDate = [NSDate date];
}
-(void)startTimer {
if (!_timer) {
_timer = [NSTimer scheduledTimerWithTimeInterval:1.0f
target:self
selector:#selector(timerFired:)
userInfo:nil
repeats:YES];
}
}
-(void)stopTimer {
if ([_timer isValid]) {
[_timer invalidate];
}
_timer = nil;
}
-(void)timerFired:(NSTimer *)timer {
NSTimeInterval elapsedTime = [[NSDate date] timeIntervalSinceDate:startDate];
NSTimeInterval remainingTime = totalCountdownInterval - elapsedTime;
CGFloat timeRemain = remainingTime;
NSLog(#"%f", timeRemain);
if (remainingTime < 0.0) {
[_timer invalidate];
}
[_circleProgressBar setHintTextGenerationBlock:(^NSString *(CGFloat progress) {
if (!(timeRemain < 0.9)) {
progress = timeRemain - 1;
return [NSString stringWithFormat:#"%.0f", progress];
}else{
progress = 0;
return [NSString stringWithFormat:#"%.0f", progress];
}
})];
[_circleProgressBar setProgress:(_circleProgressBar.progress + 0.0333f) animated:YES];
}
-(void) viewWillDisappear:(BOOL)animated {
[self stopTimer];
}
Any help will be appreciated. Thanks.
The first timer event will be fired after 1 second is passed, so you should see 29 first. So you should display the number 30 manually somehow, outside the timer event.
And you subtract 1 in your code in setHintTextGenerationBlock :
progress = timeRemain - 1;
which will make you see 28 as initial.
And as final you should start timer in viewDidAppear instead of viewWillAppear where you lose another second and come to 27.
To correct code should be like:
#interface TestViewController ()
{
NSTimeInterval totalCountdownInterval;
NSDate* startDate;
}
}
-(void)viewDidLoad {
[_circleProgressBar setHintTextGenerationBlock:(^NSString *(CGFloat progress) {
return [NSString stringWithFormat:#"%.0f", progress * 30];
})];
[_circleProgressBar setProgress:1.0) animated:NO];
}
-(void)viewDidAppear:(BOOL)animated{
[self startTimer];
totalCountdownInterval = 30.0;
startDate = [NSDate date];
}
-(void)startTimer {
if (!_timer) {
_timer = [NSTimer scheduledTimerWithTimeInterval:1.0f
target:self
selector:#selector(timerFired:)
userInfo:nil
repeats:YES];
}
}
-(void)stopTimer {
if ([_timer isValid]) {
[_timer invalidate];
}
_timer = nil;
}
-(void)timerFired:(NSTimer *)timer {
NSTimeInterval elapsedTime = [[NSDate date] timeIntervalSinceDate:startDate];
NSTimeInterval remainingTime = totalCountdownInterval - elapsedTime;
CGFloat timeRemain = remainingTime;
NSLog(#"%f", timeRemain);
if (remainingTime < 0.0) {
[_timer invalidate];
}
[_circleProgressBar setProgress:(1.0 * timeRemain / 30.0) animated:YES];
}
-(void) viewWillDisappear:(BOOL)animated {
[self stopTimer];
}
You should set progress to 1.0 in the beginning and count down to 0.0 in 30 steps.
Set hint generation block to display something meaningful for 1.0 - 0.0 as 30 - 0.
use that timer code in void view did appear and try once.
- (void)viewDidAppear:(BOOL)animated
{
[self startTimer];
totalCountdownInterval = 30.0;
startDate = [NSDate date];
}
I am trying to do the difference between time and display the countdown timer to the user in a ui label
declaration of NSTimer
#property (strong, nonatomic)NSTimer *timer;
this is my timer in view did load
_timer = [NSTimer scheduledTimerWithTimeInterval: 1.0 target:self selector:#selector(updateCountdown:) userInfo:nil repeats: YES];
and this is my updateCountdown method
-(void) updateCountdown:(int)secondsLeft {
int hours, minutes, seconds;
secondsLeft--;
hours = secondsLeft / 3600;
minutes = (secondsLeft % 3600) / 60;
seconds = (secondsLeft %3600) % 60;
_countDownlabel.text = [self timeFormatted:secondsLeft];///[NSString stringWithFormat:#"%02d:%02d:%02d", hours, minutes, seconds];
NSLog(#"%#",[NSString stringWithFormat:#"%02d:%02d:%02d", hours, minutes, seconds]);
if ( secondsLeft == 0 ) {
[_timer invalidate];
}
}
and my log details are
2017-06-30 09:49:34.070 Barebones[845:56963] requestReply cust liqour category: {
date = "30-6-2017";
"end_time" = "11:41";
"market_crash" = true;
"start_time" = "09:41";
}
2017-06-30 09:49:34.070 Barebones[845:56963] true
2017-06-30 09:49:34.070 Barebones[845:56963] 09:41
2017-06-30 09:49:34.070 Barebones[845:56963] 11:41
2017-06-30 09:49:34.070 Barebones[845:56963] 30-6-2017
2017-06-30 09:49:34.073 Barebones[845:56963] 2016-12-25 08:58:00 +0000
2017-06-30 09:49:34.073 Barebones[845:56963] 2016-12-25 12:15:00 +0000
2017-06-30 09:49:34.073 Barebones[845:56963] 197.000000 is the time difference
2017-06-30 09:49:34.073 Barebones[845:56963] 00:03:17
2017-06-30 09:49:35.075 Barebones[845:56963] 991:05:35
2017-06-30 09:49:36.075 Barebones[845:56963] 991:05:35
2017-06-30 09:49:37.075 Barebones[845:56963] 991:05:35
2017-06-30 09:49:38.075 Barebones[845:56963] 991:05:35
and this value goes on executing
Aim:- to countdown till zero and stop the timer actually I ll be hiding the label once the countdown is over
Update:-
int secondsLeft=[self timeFormatted:[date2 timeIntervalSinceDate:date1]/60];
have initialised this above timer
this is my updated timer:-
int secondsLeft=[date2 timeIntervalSinceDate:date1]/60;
NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:secondsLeft], #"cID", nil];
_timer = [NSTimer scheduledTimerWithTimeInterval: 1.0 target:self selector:#selector(updateCountdown:) userInfo:userInfo repeats: YES];
and this is my updated timer method :-
- (void)updateCountdown:(NSTimer *)timer{
int hours, minutes, seconds;
NSDictionary *userInfo = [timer userInfo];
int secondsLeft = [[userInfo objectForKey:#"cID"] intValue];
secondsLeft--;
hours = secondsLeft / 3600;
minutes = (secondsLeft % 3600) / 60;
seconds = (secondsLeft %3600) % 60;
_countDownlabel.text = [self timeFormatted:secondsLeft];///[NSString stringWithFormat:#"%02d:%02d:%02d", hours, minutes, seconds];
NSLog(#"%#",[NSString stringWithFormat:#"%02d:%02d:%02d", hours, minutes, seconds]);
if ( secondsLeft == 0 ) {
[_timer invalidate];
}
}
A couple of things.
As vadian said, if you use the selector-based timer, the timer handler function takes a single parameter which is a reference to the timer itself. If you want to keep track of the count down, you can have define properties to keep track of that:
#interface ViewController ()
#property (nonatomic, weak) IBOutlet UILabel *label;
#property (nonatomic, weak) NSTimer *timer;
#property (nonatomic, strong) NSDateComponentsFormatter *formatter;
#property (nonatomic, strong) NSDate *stopTime;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.formatter = [[NSDateComponentsFormatter alloc] init];
self.formatter.allowedUnits = NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
self.formatter.unitsStyle = NSDateComponentsFormatterUnitsStylePositional;
self.formatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorPad;
self.stopTime = [[NSDate date] dateByAddingTimeInterval:5 * 60]; // in 5 minutes, for example
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(handleTimer:) userInfo:nil repeats:true];
[self.timer fire]; // don't wait one second before firing the first time; fire now
}
- (void)handleTimer:(NSTimer *)timer {
NSDate *now = [NSDate date];
if ([now compare:self.stopTime] == NSOrderedDescending) {
// do whatever you want when timer stops
[timer invalidate];
return;
}
self.label.text = [self.formatter stringFromDate:now toDate:self.stopTime];
}
// Note, when the view disappears, invalidate the timer so the timer doesn't
// keep strong reference to the view controller. Note that in this selector-based
// pattern, I can't attempt to do this in `dealloc`, because the scheduled timer
// will keep a strong reference, preventing `dealloc` from getting called. So do
// this in `viewDidDisappear`.
- (void)viewDidDisappear:(BOOL)animated {
[self.timer invalidate];
}
#end
If only supporting iOS 10 and later, I'd suggest using the completion block timer, as it simplifies the process even further:
#interface ViewController ()
#property (nonatomic, weak) IBOutlet UILabel *label;
#property (nonatomic, weak) NSTimer *timer;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSDateComponentsFormatter *formatter = [[NSDateComponentsFormatter alloc] init];
formatter.allowedUnits = NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
formatter.unitsStyle = NSDateComponentsFormatterUnitsStylePositional;
formatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorPad;
NSDate *stopTime = [[NSDate date] dateByAddingTimeInterval:5 * 60]; // in 5 minutes, for example
typeof(self) __weak weakSelf = self; // make sure to not reference `self` in block below, but only reference `weakSelf` to avoid timer from maintaining strong reference
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 repeats:true block:^(NSTimer * _Nonnull timer) {
NSDate *now = [NSDate date];
if ([now compare:stopTime] == NSOrderedDescending) {
// do whatever you want when timer stops
[timer invalidate];
return;
}
weakSelf.label.text = [formatter stringFromDate:now toDate:stopTime];
}];
[self.timer fire]; // don't wait one second before firing the first time; fire now
}
// Because I was careful to not reference `self` inside the above block,
// this block-based timer will NOT keep a strong reference to the view
// controller. Nonetheless, when the view controller is dismissed, I want
// to stop the timer, to avoid wasting CPU cycles on a timer that isn't
// needed anymore.
- (void)dealloc {
[self.timer invalidate];
}
#end
Clearly, if you need to support iOS 9 and earlier, too, then you have to use the aforementioned selector-based solution.
I'd suggest not relying on the timer to adjust the time, as you're not assured that the timer will be called with the frequency you want. In both of the above examples, I capture to what time I'm counting down, and just display the amount of time between "now" and that scheduled "stop time".
Note, I'm also suggesting that you get out of the business of building the format string yourself. There's a convenient NSDateComponentsFormatter which can format this for you. Use it, if you can.
You made your timer reference strong. You can make it weak because a scheduled timer is not deallocated until it's invalidated. And once it's invalidated, it's convenient to have it be deallocated automatically for you.
Your action method cannot work.
If a parameter is passed it must be a NSTimer instance
- (void)updateCountdown:(NSTimer *)timer
To pass custom parameters use the userInfo argument.
Nevertheless a more suitable solution is to use an instance variable or property because the value of userInfo must be an object like NSNumber
Create property
#property (nonatomic) int secondsLeft;
in viewDidLoad
self.secondsLeft = 5 * 60; // 5 minutes
_timer = [NSTimer scheduledTimerWithTimeInterval: 1.0 target:self selector:#selector(updateCountdown) userInfo:nil repeats: YES];
Selector:
-(void)updateCountdown{
int secondsLeft = self.secondsLeft;
if (secondsLeft >= 0) {
int minutes, seconds;
int hours;
self.secondsLeft--;
hours = secondsLeft / 3600;
minutes = (secondsLeft % 3600) / 60;
seconds = (secondsLeft %3600) % 60;
NSString *time = [NSString stringWithFormat:#"%02d:%02d:%02d", hours, minutes, seconds];
_countDownlabel.text = [self timeFormatted:secondsLeft];
}
if (secondsLeft <= 0) {
NSLog(#"TIME ENDS");
if ([self.timer isValid]) {
[self.timer invalidate];
self.timer = nil;
}
}
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
i have a view controller in that i want to display time in reverse order.my default time is 00:59:59? i want output like this (00:58:00,00:57:00,00:56:00,00:30:00)?
int currentTimeInSeconds;
NSTimer *myTimer;
if (!timeLabel)
{
timeLabel =0;
}
if (!myTimer)
{
myTimer = [self createTimer];
}
-(NSTimer *)createTimer
{
return [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(timerTicked) userInfo:nil repeats:YES];
}
-(void)timerTicked
{
if (currentTimeInSeconds == 0)
{
[myTimer invalidate];
currentTimeInSeconds = 60;
timeLabel.text = [self formattedTime:currentTimeInSeconds];
}
else
{
currentTimeInSeconds--;
self.timeLabel.text = [self formattedTime:currentTimeInSeconds];
}
}
-(NSString *)formattedTime:(int)totalSeconds
{
int seconds = totalSeconds%60;
int minutes = (totalSeconds/60)%60;
int hours = totalSeconds/3600;
return [NSString stringWithFormat:#" %02d:%02d:%02d",hours,minutes,seconds];
}
- (IBAction)btnStart:(id)sender {
timet=[self.txtTime.text integerValue];
self.lblTime.text=[NSString stringWithFormat:#"%lu", (unsigned long)timet];
[NSTimer scheduledTimerWithTimeInterval:timet
target:self
selector:#selector(targetMethod)
userInfo:nil
repeats:NO];
[self time];
}
-(void)time
{
[NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:#selector(targetMethod2)
userInfo:nil
repeats:NO];
}
-(void)targetMethod
{
NSLog(#"STOP");
UIAlertView *alert=[[UIAlertView alloc]initWithTitle:#"Stop" message:#"Time is over" delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil];//, nil
[alert show];
}
-(void)targetMethod2
{
if(timet!=0)
{
timet-=1;
NSLog(#"%lu",(unsigned long)timet);
self.lblTime.text=[NSString stringWithFormat:#"%lu",(unsigned long)timet];
[self time];
}
}
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 0)
{
self.txtTime.text=nil;
self.lblTime.text=nil;
}
}
---------------- Second code ---------------------
#interface ViewController ()
{
UILabel *progress;
NSTimer *timer;
int currMinute;
int currSeconds;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
progress=[[UILabel alloc] initWithFrame:CGRectMake(80, 15, 100, 50)];
progress.textColor=[UIColor redColor];
[progress setText:#"Time : 3:00"];
progress.backgroundColor=[UIColor clearColor];
[self.view addSubview:progress];
currMinute=3;
currSeconds=00;
[self start];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)start
{
timer=[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(timerFired) userInfo:nil repeats:YES];
}
-(void)timerFired
{
if((currMinute>0 || currSeconds>=0) && currMinute>=0)
{
if(currSeconds==0)
{
currMinute-=1;
currSeconds=59;
}
else if(currSeconds>0)
{
currSeconds-=1;
}
if(currMinute>-1)
[progress setText:[NSString stringWithFormat:#"%#%d%#%02d",#"Time : ",currMinute,#":",currSeconds]];
}
else
{
[timer invalidate];
}
}
- (IBAction)startCountdown:(id)sender {
//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(updateCounterLabel)
userInfo:nil
repeats:YES];
}
Every 1 Sec call following function.
-(void)timerTicked
{
NSString *dateString = #"12-12-2015";
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"dd-MM-yyyy"];
NSDate *dateFromString = [[NSDate alloc] init];
dateFromString = [dateFormatter dateFromString:dateString];
NSDate *now = [NSDate date];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *componentsHours = [calendar components:NSHourCalendarUnit fromDate:now];
NSDateComponents *componentMint = [calendar components:NSMinuteCalendarUnit fromDate:now];
NSDateComponents *componentSec = [calendar components:NSSecondCalendarUnit fromDate:now];
NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *componentsDaysDiff = [gregorianCalendar components:NSDayCalendarUnit
fromDate:now
toDate:dateFromString
options:0];
long day = (long)componentsDaysDiff.day;
long hours = (long)(24-componentsHours.hour);
long minutes = (long)(60-componentMint.minute);
long sec = (long)(60-componentSec.second);
NSString *strForday = [NSString stringWithFormat:#"%02ld",day];
NSString *strForhours = [NSString stringWithFormat:#"%02ld",hours];
NSString *strForminutes = [NSString stringWithFormat:#"%02ld",minutes];
NSString *strForsec = [NSString stringWithFormat:#"%02ld",sec];
NSLog(#"%# %# %# %# ",strForday,strForhours,strForminutes,strForsec);
if (day == 0 && hours == 0 && minutes == 0 && sec == 0) {
[myTimer invalidate];
}
}
I have an NSTimer which I pause and resume with the following methods respectively:
-(void) pauseTimer:(NSTimer *)timer {
self.scene.paused = YES;
pauseStart = [NSDate date];
previousFireDate = [timer fireDate];
[timer setFireDate:[NSDate distantFuture]];
}
-(void) resumeTimer:(NSTimer *)timer {
self.scene.paused = NO;
NSDate *currentDate = [NSDate date];
NSTimeInterval pauseTime = [currentDate timeIntervalSinceDate:pauseStart];
NSDate *neededFireDate = [NSDate dateWithTimeInterval:pauseTime sinceDate:previousFireDate];
[timer setFireDate:neededFireDate];
NSLog(#"Fire Date: %#", timer.fireDate); //returning null
}
It is not properly resetting the fire date because when I check timer.fireDate, it says null. All we want is for these methods to pause the timer and resume the timer where it left off when the resume method is called. Any help is greatly appreciated.
My solution differs from yours in one major thing. I recreate a timer when it resumes. Here is how I do it and it's been working quite well:
#property (nonatomic, strong) NSTimer *timer;
#property (nonatomic, assign) NSTimeInterval elapsedTime;
#property (nonatomic, strong) NSDate *startDate;
- (void)startTimer
{
NSTimeInterval timeInterval = 20.0f;
// Create a timer. Adjust the elapsed time.
_timer = [NSTimer scheduledTimerWithTimeInterval:(timeInterval - _elapsedTime)
target:self
selector:#selector(timerFireMethod:)
userInfo:nil
repeats:YES];
// Save the start date.
_startDate = [NSDate date];
}
- (void)timerFireMethod:(NSTimer *)theTimer
{
// Clean.
[_timer invalidate];
_timer = nil;
_elapsedTime = 0.0;
[self startTimer];
// Additional handling.
}
- (void)pauseTimer
{
// Clean.
[_timer invalidate];
_timer = nil;
// Save the elapsed time.
_elapsedTime = [[NSDate date] timeIntervalSinceDate:_startDate];
}
Hope it helps.