Search code examples
iosobjective-ctimernstimer

NSTimer is sometimes getting fired before time


I'm setting a timer to fire a method after 30 sec if a specific condition is not met else/otherwise the timer would be invalidated. Here's is what i am doing I am creating a timer property like this

@property (nonatomic) NSTimer *timer;

Now in some method i am starting my timer like this

- (void) createAPIXML
{
    if (_isGenerateRootTag) {
        _root = (DDXMLElement *) [DDXMLNode elementWithName:[[MainViewController sharedViewController] rootElement]];
    _isGenerateRootTag = FALSE;
}
    dispatch_async(dispatch_get_main_queue(), ^{
    _timer = [NSTimer scheduledTimerWithTimeInterval:30.0 target:self selector:@selector(timerFireMethod) userInfo:nil repeats:NO];
    NSLog(@"**************************STARTING THE TIMER %@**********************",_timer.description);
});
[self sendRequest];
}

Now, i proceed further do my validations and if all the conditions are met i invalidate my timer from some other methods like this

NSLog(@"**************************KILLING TIMER %@ FROM VALIDATE RESPONSE METHOD**********************",_timer.description);
        // Invalidate timer..
        if (_timer != nil) {
            [_timer invalidate];
            _timer = nil;
        }

If the conditions are not met and 30 sec are passsed my timerFireMethod would get called

- (void)timerFireMethod
{
NSLog(@"Timer Methods Metho gor called with timer Instance %@",_timer.description);
}

This is an intermittent issue, looks like a race condition to me but does happen and causes a lot of problem.. Am i doing something wrong here need your expert advices.. I am stuck


Solution

  • It looks like you have to invalidate the timer before reassigning it source: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSTimer_Class/

    Once scheduled on a run loop, the timer fires at the specified interval until it is invalidated.

    So, do something like

    dispatch_async(dispatch_get_main_queue(), ^{
        if (timer) { 
             [_timer invalidate];
             _timer = nil;
        }
        _timer = [NSTimer scheduledTimerWithTimeInterval:30.0 target:self selector:@selector(timerFireMethod) userInfo:nil repeats:NO];
    

    i.e. reassinging the timer is not invaliding the old one, also be sure to

    you should always call the invalidate method from the same thread on which the timer was installed.