How to implment laps in Stop Watch iphone app

2019-07-18 22:34发布

问题:

I am building one application which has stop watch as its accessory function. I am trying to do something very similar to iOS stop watch. I got stop, reset functionality working but I could not get start (once it stop and user click on start) and lap functions working properly. I tried to look around for this problem but I could not find anything besides one time start and reset stop watch tutorials.Here is what I have right now. Can anyone help me out here with this functions ?

// Stop Watch Code Begins

- (void)updateTimer
{
NSDate *currentDate = [NSDate date];
NSTimeInterval timeInterval = [currentDate timeIntervalSinceDate:startDate];
NSDate *timerDate = [NSDate dateWithTimeIntervalSince1970:timeInterval];

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"HH:mm:ss.SSS"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0.0]];
NSString *timeString=[dateFormatter stringFromDate:timerDate];
stopWatchLable.text = timeString;
[dateFormatter release];

}

 -(IBAction)startTapped:(id)sender
{
if ([self.start.titleLabel.text isEqualToString:@"Start"])
{
    NSLog(@"Start Tapped");
    [self.start setTitle:@"Stop" forState:UIControlStateNormal];
    [self.reset setTitle:@"Lap" forState:UIControlStateNormal];

    self.startDate =[NSDate date];
    stopWatchTimer = [NSTimer scheduledTimerWithTimeInterval:1.0/10.0
                                                      target:self
                                                    selector:@selector(updateTimer)
                                                    userInfo:nil
                                                     repeats:YES];

 }
else if ([self.start.titleLabel.text isEqualToString:@"Stop"])
{
    NSLog(@"Stop Tapped");
    [self.start setTitle:@"Start" forState:UIControlStateNormal];
    [self.reset setTitle:@"Reset" forState:UIControlStateNormal];

    [stopWatchTimer invalidate];
    stopWatchTimer = nil;
    [self updateTimer]; 
}
}
-(IBAction)resetTapped:(id)sender
{   
if ([self.reset.titleLabel.text isEqualToString:@"Reset"])
{
    NSLog(@"Reset Tapped");
    [stopWatchTimer invalidate];
    stopWatchTimer = nil;
    [stopWatchLable setText:@"00:00:00.000"];
}
else if ([self.reset.titleLabel.text isEqualToString:@"Lap"])
{
    NSLog(@"Lap Tapped");        
}
}
-(IBAction)hideTapped:(id)sender
{
CGRect screenRect = [[UIScreen mainScreen] applicationFrame];
CGRect endFrame = self.stopWatchView.frame;
endFrame.origin.y = screenRect.origin.y + screenRect.size.height;

// start the slide down animation
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3];

// we need to perform some post operations after the animation is complete
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(slideDownDidStop)];

self.stopWatchView.frame = endFrame;
[UIView commitAnimations];

// grow the table back again in vertical size to make room for the date picker
CGRect newFrame = self.tableView.frame;
newFrame.size.height += self.stopWatchView.frame.size.height;
self.tableView.frame = newFrame;
//self.tableView.frame = screenRect;

[stopWatchTimer invalidate];
stopWatchTimer = 0;
[stopWatchLable setText:@"00:00:00.000"];
[self updateTimer];
}

回答1:

Don't take this the wrong way, but you have one bad design choice in your code: You should not rely on a button text to tell you what you want to do – if at some point in the future you localize your application you'll have to redo the timer.

That said, here's how I would implement a stopwatch: You need two instance variables, NSTimer timer and NSDate startDate. For a lap function you'll need another one, an NSMutableArray laps. Your two buttons are fine, using simple logic you can decide what you have to do when tapping (untested code!):

Start/Stop button

if (!timer) {
    self.startDate = [NSDate date];
    self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 / 10.0
                                                  target:self
                                                selector:@selector(updateTimer)
                                                userInfo:nil
                                                 repeats:YES];
    [self updateTimer];
    // set button text to STOP and LAP
}

// there already is a timer, stopwatch running, so we want to stop
else {
    if ([timer isValid]) {
        [timer invalidate];
    }
    self.timer = nil;
    [self updateTimer];
    // set button text to START and RESET
}

Reset/Lap button

// if we have a timer, we want to take a lap
if (timer) {
    if (!laps) {
        self.laps = [NSMutableArray array];
    }
    [laps addObject:[NSDate date]];
    [self updateTimer];
}

// there is no timer, so we want to reset
else {
    self.startDate = nil;
    [self updateTimer];

    // delete all laps
    self.laps = nil;
}

Now you only have to modify updateTimer to do what you want it to do. In updateTimer, you should also check whether startDate is nil or not before you calculate anything. For the laps you can just loop over the laps array and calculate the difference between startDate and the date in the array, or even between the dates in the array.

I hope this helps!