Question

Ok so I have two view controllers in my app. On the first one there is a timer and on the second a stopwatch. How do i keep the timers going for the different views when i am switching between them?

At the moment when i change view the timer stops and everything resets.

First views .m file:

#import "ViewController.h"
#import <AudioToolbox/AudioToolbox.h>

@interface ViewController ()

//TIMER
//labels
@property (weak, nonatomic) IBOutlet UILabel *timeLabelHour;
@property (weak, nonatomic) IBOutlet UILabel *timeLabelMin;
@property (weak, nonatomic) IBOutlet UILabel *timeLabel;
//buttons
@property (weak, nonatomic) IBOutlet UIBarButtonItem *timerWindow;
@property (weak, nonatomic) IBOutlet UIBarButtonItem *stopwatchWindow;
@property (weak, nonatomic) IBOutlet UIButton *stop;
@property (weak, nonatomic) IBOutlet UIButton *start;
@property (weak, nonatomic) IBOutlet UIButton *reset;
//steppers
@property (weak, nonatomic) IBOutlet UIStepper *stepper;
@property (weak, nonatomic) IBOutlet UIStepper *Minstepper;
@property (weak, nonatomic) IBOutlet UIStepper *Hourstepper;




@end

@implementation ViewController

-(void) timerRun{

if(pause == NO){
    overall = overall - 1;



    int hours = overall / 3600;
    int minutes = overall - (hours * 3600);
    int minCon = minutes / 60;
    int seconds = minutes - (minCon * 60);

    NSString *timerOutputHour = [NSString stringWithFormat:@"%d", hours];
    NSString *timerOutputMin = [NSString stringWithFormat:@"%02d", minCon];
    NSString *timerOutput = [NSString stringWithFormat:@"%02d", seconds];

    self.timeLabelHour.text = timerOutputHour;
    self.timeLabelMin.text = timerOutputMin;
    self.timeLabel.text = timerOutput;


    if(overall == 0){

        [Countdown invalidate];
        Countdown = nil;

        UILocalNotification *timeFinNotification = [[UILocalNotification alloc] init];
        timeFinNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow: 1];
        timeFinNotification.alertBody = @"Your timer has finished";
        timeFinNotification.timeZone = [NSTimeZone defaultTimeZone];
        [[UIApplication sharedApplication] scheduleLocalNotification:timeFinNotification];

        AudioServicesPlayAlertSound(kSystemSoundID_Vibrate);

        self.Hourstepper.enabled = YES;
        self.Minstepper.enabled = YES;
        self.stepper.enabled = YES;

        timer = 0;
        timerMin = 0;

        self.start.enabled = YES;
        self.stop.enabled = NO;
        self.reset.enabled = NO;

    }
}

}

-(void) setTimer{

overall = (timerMin * 60) + (timerHour * 60 * 60) + timer;


Countdown = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerRun) userInfo:nil repeats:YES];

self.Hourstepper.enabled = NO;
self.Minstepper.enabled = NO;
self.stepper.enabled = NO;


}

- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.

self.stepper.autorepeat = YES;
self.stepper.wraps = YES;
self.stepper.minimumValue = 0;
self.stepper.maximumValue = 59;
self.stepper.stepValue = 1;

self.Minstepper.autorepeat = YES;
self.Minstepper.wraps = YES;
self.Minstepper.minimumValue = 0;
self.Minstepper.maximumValue = 59;
self.Minstepper.stepValue = 1;

self.Hourstepper.autorepeat = YES;
self.Hourstepper.wraps = YES;
self.Hourstepper.minimumValue = 0;
self.Hourstepper.maximumValue = 23;
self.Hourstepper.stepValue = 1;

self.start.enabled = YES;
self.stop.enabled = NO;
self.reset.enabled = NO;

timer = self.stepper.value;
timerMin = self.Minstepper.value;
timerHour = self.Hourstepper.value;


}



- (IBAction)start:(id)sender{
if(pause == NO && (timer != 0 || timerMin != 0 || timerHour != 0)){
    [self setTimer];
}
pause = NO;
if(timer != 0 || timerMin != 0 || timerHour != 0){
    self.start.enabled = NO;
    self.stop.enabled = YES;
    self.reset.enabled = YES;
}

}

- (IBAction)stop:(id)sender{
pause = YES;
self.start.enabled = YES;
self.stop.enabled = NO;
self.reset.enabled = YES;
}

- (IBAction)reset:(id)sender{

[Countdown invalidate];
Countdown = nil;


self.Hourstepper.enabled = YES;
self.Minstepper.enabled = YES;
self.stepper.enabled = YES;

self.timeLabelHour.text = @"0";
self.timeLabelMin.text = @"00";
self.timeLabel.text = @"00";

self.stepper.value = 0;
self.Minstepper.value = 0;
self.Hourstepper.value = 0;

timer = 0;
timerMin = 0;
timerHour = 0;

pause = NO;

self.start.enabled = YES;
self.stop.enabled = NO;
self.reset.enabled = NO;
}

- (IBAction)stepperValueChanged:(UIStepper *)sender
{
timer = sender.value;
self.timeLabel.text = [NSString stringWithFormat:@"%02d",timer];
}

- (IBAction)stepperValueChangedMin:(UIStepper *)sender
{
timerMin = sender.value;
self.timeLabelMin.text = [NSString stringWithFormat:@"%02d",timerMin];
}

- (IBAction)stepperValueChangedHour:(UIStepper *)sender
{
timerHour = sender.value;
self.timeLabelHour.text = [NSString stringWithFormat:@"%d",timerHour];
}

- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}


#pragma mark iAd Delegate Mathods

-(void)bannerViewDidLoadAd:(ADBannerView *)banner{

[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1];
[banner setAlpha:1];
[UIView commitAnimations];

}

-(void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error{

[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1];
[banner setAlpha:0];
[UIView commitAnimations];

}

@end

Second Views .m file:

#import "ViewControllerStopwatch.h"

@interface ViewControllerStopwatch ()

//STOPWATCH
//labels
@property (weak, nonatomic) IBOutlet UILabel *stopLabelHour;
@property (weak, nonatomic) IBOutlet UILabel *stopLabelMin;
@property (weak, nonatomic) IBOutlet UILabel *stopLabel;
@property (weak, nonatomic) IBOutlet UILabel *stopLabelMilli;

//buttons
@property (weak, nonatomic) IBOutlet UIBarButtonItem *timerWindow;
@property (weak, nonatomic) IBOutlet UIBarButtonItem *stopwatchWindow;
@property (weak, nonatomic) IBOutlet UIButton *start;
@property (weak, nonatomic) IBOutlet UIButton *reset;
@property (weak, nonatomic) IBOutlet UIButton *stop;


@end

@implementation ViewControllerStopwatch

-(void) timerRun{

if(pause == NO){


    overall = overall + 1;

    hours = overall / 3600;
    minutes = overall - (hours * 3600);
    minCon = minutes / 60;
    seconds = minutes - (minCon * 60);

    NSString *timerOutputHour = [NSString stringWithFormat:@"%d", hours];
    NSString *timerOutputMin = [NSString stringWithFormat:@"%02d", minCon];
    NSString *timerOutput = [NSString stringWithFormat:@"%02d", seconds];

    self.stopLabelHour.text = timerOutputHour;
    self.stopLabelMin.text = timerOutputMin;
    self.stopLabel.text = timerOutput;

}

}

-(void) timerRunMilli{

if(pause == NO){


    overallMilli = overallMilli + 1;

    milliseconds = overallMilli;

    if(overallMilli >= 99){
        overallMilli = 0;
    }

    NSString *timerOutputMilli = [NSString stringWithFormat:@"%02d", milliseconds];

    self.stopLabelMilli.text = timerOutputMilli;

}

}

-(void) setTimer{

Countdown = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerRun) userInfo:nil repeats:YES];

CountdownMilli = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(timerRunMilli) userInfo:nil repeats:YES];
}


- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.

self.start.enabled = YES;
self.stop.enabled = NO;
self.reset.enabled = NO;


}

- (IBAction)start:(id)sender{
if(pause == NO){
    [self setTimer];
}
pause = NO;

self.start.enabled = NO;
self.stop.enabled = YES;
self.reset.enabled = YES;


}
- (IBAction)stop:(id)sender{
pause = YES;

self.start.enabled = YES;
self.stop.enabled = NO;
self.reset.enabled = YES;
}

- (IBAction)reset:(id)sender{

[Countdown invalidate];
Countdown = nil;

[CountdownMilli invalidate];
CountdownMilli = nil;


self.stopLabelHour.text = @"0";
self.stopLabelMin.text = @"00";
self.stopLabel.text = @"00";
self.stopLabelMilli.text = @"00";

overall = 0;
overallMilli = 0;

pause = NO;


self.start.enabled = YES;
self.stop.enabled = NO;
self.reset.enabled = NO;
}

- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}

#pragma mark iAd Delegate Mathods

-(void)bannerViewDidLoadAd:(ADBannerView *)banner{

[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1];
[banner setAlpha:1];
[UIView commitAnimations];

}

-(void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error{

[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1];
[banner setAlpha:0];
[UIView commitAnimations];

}



@end
Was it helpful?

Solution

You shouldn't keep the timer running in the view that isn't on display. When the view disappears the timer should be stopped and when the view appears (if the timer should be running) the timer should be restarted.

To do this, you should be using NSDate to record when the timer was started so that you can calculate how long it's been running for. The only reason you need to keep the timer running really is to process overall = overall - 1;.

Now, the above is more complex, and you need to add more logic into how you handle pause (there are other answers to pause with NSTimer on SO). But, it's a lot cleaner and it's more accurate (the timer fire rate isn't 100% guaranteed).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top