May Yang
May Yang

Reputation: 523

NSTimer's [timer fire] doesn't work

I have a NSTimer that works fine and counts down in 1 second intervals. But I want the timer to trigger immediately without that 1 second delay.

I thought calling [timer fire] should work for this (described here) but it doesn't make a difference. I want the timer to be triggered as fast as if I scheduled the interval to be 0.

- (void)onStartButtonPressed:(UIButton*)sender
{
    CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:tv];
    NSIndexPath* indexPath = [tv indexPathForRowAtPoint:buttonPosition];
    NSInteger index = indexPath.row;

//  starts timer for cell at the index path
if (indexPath != nil)
{
    NSTimer* timer = [timerArray objectAtIndex: index];
    if ([timer isEqual:[NSNull null]]) {
        NSLog(@"It's empty");

        // start timer
        NSTimer timer = [NSTimer   scheduledTimerWithTimeInterval:1.0
                                                            target:self
                                                          selector:@selector(onTick:)
                                                          userInfo:indexPath
                                                           repeats:YES];

//            [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

        NSLog(@"before timer fire");
        [timer fire];


        // update data array of timer objects and countdowns
        NSInteger selectedTimeIdx = [[selectedTimeIdxArray objectAtIndex: index] integerValue];
        NSInteger selectedTime = [pickerTimeArray[selectedTimeIdx] integerValue];
        [timerArray replaceObjectAtIndex:index withObject:timer];
        [countdownArray replaceObjectAtIndex:index withObject:[NSNumber numberWithInteger:selectedTime*60]];
    } else {
        NSLog(@"It's not empty");
    }
}

- (void)onTick:(NSTimer *)timer
{
    NSLog(@"on tick method starts");

    // get the timer's owner's index path and update label
    NSIndexPath* indexPath = [timer userInfo];
    NSInteger index = indexPath.row;

    // update countdown
    NSInteger countdown = [[countdownArray objectAtIndex: index] integerValue];
    [countdownArray replaceObjectAtIndex:index withObject:[NSNumber numberWithInteger:--countdown]];


//    NSLog(@"countdown: %ld", (long)countdown);


    [tv reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];


//    NSLog(@"Tic indexPath: %@", indexPath);


    if (countdown == 0)
    {
        [timer invalidate];
        timer = nil;
    }
}

The timer works but I don't want there to be a 1 second delay for it to be initially triggered. I want the timer to start immediately.

Edit: I added logs that rmaddy suggested. Here are my results (I changed the interval time to 3):

2015-05-19 14:41:02.827 restaurant[4206:77915] before timer fire

2015-05-19 14:41:02.827 restaurant[4206:77915] on tick method starts

2015-05-19 14:41:05.827 restaurant[4206:77915] on tick method starts

2015-05-19 14:41:08.828 restaurant[4206:77915] on tick method starts

Upvotes: 0

Views: 604

Answers (2)

May Yang
May Yang

Reputation: 523

Some of the comments were really helpful, especially adding the logs as suggested by rmaddy. It turns out [timer fire] was working fine.

I had confused myself because my timerLabel which displayed the countdown was being updated in my cell with a 1 second delay, and I thought that meant the timer instantiation was delayed.

Once I saw what the problem really was, all I had to do was update the cell in the same block that I instantiated the timer (instead of just onTick).

I just added this to my onStartButtonPressed and everything works as I want it to.

        // update countdown
        NSInteger countdown = [[countdownArray objectAtIndex: index] integerValue];
        [countdownArray replaceObjectAtIndex:index withObject:[NSNumber numberWithInteger:--countdown]];

        // cell label gets updated right at start button press
        [tv reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];

Leaving here in case it helps anyone.

Upvotes: 0

AppyMike
AppyMike

Reputation: 2064

Why not just call your method before the timer

[self onTick:nil];
//usual timer code here

Edit: as stated by rmaddy

NSTimer *timer = [NSTimer   scheduledTimerWithTimeInterval:1.0
                                                        target:self
                                                      selector:@selector(onTick:)
                                                      userInfo:indexPath repeats:YES];

[self onTick:timer];

Upvotes: 1

Related Questions