How to remove timer from runloop immediately

I have a timer called after 5 seconds added to the global queue, although I am invalidated after a 2 second loop that doesn't end until 5 seconds. In the following snippet, backgroundTimer is an instance of var and run is a member function. What's wrong with the following code, which blocks the completion of the run loop.

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

    _backgroundTimer = [NSTimer timerWithTimeInterval:5 target:self selector:@selector(run) userInfo:nil repeats:NO];
    [ [NSRunLoop currentRunLoop] addTimer:_backgroundTimer forMode:NSRunLoopCommonModes];
    [[NSRunLoop currentRunLoop] run];

    NSLog(@"Run loop terminated");

});

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    [_backgroundTimer invalidate];
    _backgroundTimer=nil;

});

      

+3


source to share


2 answers


The first problem is that your timer is being added to a run loop on an arbitrary background thread. (i.e. the thread will be created by GCD to serve the background queue). You can do it, but it doesn't make any sense.

As an aside, you said that you want this startup loop to end, but in the documentation for the method, -run

it says this:

Removing all known sources and timers manually from the trigger cycle is not a guarantee of exiting the trigger cycle. OS X can install and remove additional input sources as needed to process the requested targets in the sink stream. Thus, these sources can start a loop from the output.

If you want to end the run loop, you shouldn't use this method. Use one of the other triggering methods instead, and also check for other arbitrary conditions in the loop.



You will need to format the event loop yourself if you want to exit when the timer is invalid. For example:

while (_backgroundTimer.valid && [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow: 0.1]]);

      

This will exit the start cycle for a maximum of 0.1 (- epsilon) seconds after the timer is canceled.

+3


source


Try it like this:

[NSRunLoop cancelPreviousPerformRequestsWithTarget:self selector:@selector(run) object:nil];

      



Edited:

-(void)run{
   if(taskComplete){
      [_backgroundtimer invalidate];   
}

      

0


source







All Articles