0

Currently, I have a countdown timer running. The code I use is below.

What I need help on, is finding out when the countdown is over (zero time left).

I can't quite figure it out. I need to get it so I can send a push notification when the countdown is over.

Thanks for the help!!

- (IBAction)startCountdown:(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 seconds = ti % 60;
    NSInteger minutes = (ti / 60) % 60;
    NSInteger hours = (ti / 3600) % 24;
    NSInteger days = (ti / 86400);

    //Update the lable with the remaining time
    self.countdownLabel.text = [NSString stringWithFormat:@"%02i days %02i hrs %02i min %02i sec", days, hours, minutes, seconds];
}

UPDATE This is what I've tried so far:

- (void) bothDatesEqual {

    if ([_countdownLabel.text isEqualToString:@"00 days 00 hrs 00 min 00 sec"]) {
        NSLog(@"No time left");
    }
    else {
        NSLog(@"Some time left");
    }
}

UPDATE 2 This is what I changed per DanH

- (void)startCountdownDate {

    //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]];

    [self updateTime];

    NSTimer *timerDate;
    timerDate  = [NSTimer scheduledTimerWithTimeInterval:1.0
                                             target:self
                                                selector:@selector(updateTimeDate:)
                                           userInfo:nil
                                            repeats:YES];

}

-(void)updateTime
{
    //Get the time left until the specified date
    NSInteger ti = ((NSInteger)[self.datePicker.date timeIntervalSinceNow]);
    NSInteger seconds = ti % 60;
    NSInteger minutes = (ti / 60) % 60;
    NSInteger hours = (ti / 3600) % 24;
    NSInteger days = (ti / 86400);

    //Update the label with the remaining time
    _countdownLabel.text = [NSString stringWithFormat:@"%02i days %02i hrs %02i min %02i sec", days, hours, minutes, seconds];
}

- (void)updateTimeDate:(NSTimer *)timerDate {

    NSDate *now = [NSDate date];
    NSDate *targetDate = self.datePicker.date;

    if (now == [now laterDate:targetDate]) {
        // the current time is >= targetDate
        [timerDate invalidate];
    }
}
rmaddy
  • 314,917
  • 42
  • 532
  • 579
Realinstomp
  • 532
  • 2
  • 13
  • 30
  • What have you tried and what are you stuck on? You appear to e able to calculate the time remaining. How can you use that to check if no time remains? – Jonah Jul 25 '14 at 01:58
  • Jonah, thanks for the response! I updated my question to show what I've tried so far. Any ideas? – Realinstomp Jul 25 '14 at 02:10
  • That's a start but why don't you think it works. What d&d you expect to see happen and what did you observe instead? What do you think that means is going on? Is "bothDatesEqual" being called? If so what is it doing which you did not expect? – Jonah Jul 25 '14 at 02:18
  • It's always logging "Some Time Left" even when there is "No time Left". And I've got no idea why. Racking my brain. – Realinstomp Jul 25 '14 at 02:25
  • Timers are not exact. What do you suppose happens if your timer does not fire on the exact second you expected it to end? – Jonah Jul 25 '14 at 05:17
  • No idea, I guess that's why I'm asking and trying to find out because I'm assuming whatever I'm doing is not correct. – Realinstomp Jul 25 '14 at 13:31

1 Answers1

1

The better way to use an NSTimer is to think of it as a pulse, not a source of time. The correct source of time is [NSDate date]. So the way to proceed is to set the timer, change your UI when the timer fires, and test:

// updateTime
// give the selector a colon when you schedule the timer and when you implement it
// that will give you access to the timer

-(void)updateTime:(NSTimer *)timer {

    NSDate *now = [NSDate date];
    NSDate *targetDate = self.datePicker.date;

    if (now == [now laterDate:targetDate]) {
        // the current time is >= targetDate
        [timer invalidate];
    }

    // the rest of your updateTime logic here, but see below...

Remember, to change give the selector a parameter (colon) when you schedule...

selector:@selector(updateTime:)

As an aside, Here's a good SO answer on a more solid approach for extracting time components from an NSTimeInterval.

EDIT- The better answer about time is buried down in that question (not the marked as the correct answer or the most up-voted). In essence...

NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [gregorianCalendar components: (NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit | NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit )
                                                    fromDate:targetDate
                                                      toDate:now
                                                     options:0];
NSLog(@"%ld", [components year]);
NSLog(@"%ld", [components month]);
NSLog(@"%ld", [components day]);
NSLog(@"%ld", [components hour]);
NSLog(@"%ld", [components minute]);
NSLog(@"%ld", [components second]);
Community
  • 1
  • 1
danh
  • 62,181
  • 10
  • 95
  • 136
  • Hey thanks for the response. I think I'm tracking somewhat with this but trying to fully figure it out. Are you saying to replace what I have currently as my timer too? – Realinstomp Jul 25 '14 at 02:19
  • As a minimal step, add that terminal condition to your timer code. It will correctly say when the targetDate has been reached, which I think is your original question. Then, since you want to terminate the timer at that time, I'm suggesting you also include the timer as a parameter (by adding the colon). Last, some advice that you can use later on the proper way to format the time components. – danh Jul 25 '14 at 02:24
  • `give the selector a colon when you schedule the timer and when you implement it ` does that mean something for the code I've already written, or is it an explanation of something you added? – Realinstomp Jul 25 '14 at 02:28
  • About your code. You should pass the timer to the firing method so that you can invalidate it. – danh Jul 25 '14 at 02:44
  • See my code above in Update 2, is that what your talking about? – Realinstomp Jul 25 '14 at 02:46
  • Yes. Good. Then whatever code you choose to get time components still can go in the updateTime: method. – danh Jul 25 '14 at 02:53
  • Cool. So I feel like I have the code correct, but the countdown label is not updating as I move the DatePicker. It gets set immediately, but doesn't update when scrolling the DatePicker. Which I don't understand because I still am calling `updateTime` like you suggested too. I can't figure out what else it would be? – Realinstomp Jul 25 '14 at 02:56