简体   繁体   中英

How to run NSTimer in background Thread

I would like to run NSTimer using BackGround thread for that I have written below code but my NSTimer method is not get calling!

can some one help me please

- (void)viewDidLoad {
       [super viewDidLoad];
       // Do any additional setup after loading the view.
        NSOperationQueue* operationQueue = [[NSOperationQueue alloc] init];
        [operationQueue addOperationWithBlock:^{
        // Perform long-running tasks without blocking main thread

        [NSTimer scheduledTimerWithTimeInterval:2
                                                 target:self
                                               selector:@selector(targetMethod)
                                               userInfo:nil
                                                repeats:YES];
          }];
}

-(void)targetMethod{
         NSLog(@"Timer Called");
}

You can use GCD dispatch queue for BackGround thread :=

 dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void)
                   {
                       NSTimer *timer = [NSTimer timerWithTimeInterval:0.5
                                                                target:self
                                                              selector:@selector(timerFired)
                                                              userInfo:nil repeats:YES];
                       [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
                       dispatch_async(dispatch_get_main_queue(), ^(void)
                                      {
                                      });
                   });

Krish, you seem to be getting yourself on a wrong path here.

First, you should create timers while on the main thread by just calling scheduledTimerWithTimeInterval. Putting the call scheduledTimerWithTimerInterval onto an operationQueue is pointless. Timers are called from their thread's runloop. Trying to dispatch them with a different operationQueue will get you into trouble.

If you want the actual operation of a timer to happen in the background, then use dispatch_async (...) in your timer callback method to run code in the background.

Unless you have a legitimate reason to do otherwise, schedule your timer on the main thread.

Your callback method should have a parameter for the timer. That way your callback method can manipulate the timer, for example by invalidating it. scheduledTimer... also returns the timer. Usually you would store that timer object so that you can invalidate it when your view disappears. If you don't do that, you will get a new NSTimer every time viewDidLoad is called. That is you will have more and more timer callbacks running as your app is running.

Learn GCD (grand central dispatch). It is much, much simpler than operation queues. You shouldn't use operation queues unless you have a real good reason.

When you ask "how do we stop the background thread" - you don't. You dispatch code to it, the code runs, and as long as there is code dispatched, it will run. If there is no code dispatched the the background, it stops running until you dispatch code again. That's how it is supposed to work.

If you meant "how do I stop the timer" - that's what invalidate does.

PS. If you wanted to schedule a timer from a background thread (which you don't want, believe me), a correct answer can be found here: iOS5 ARC is it safe to schedule NSTimers from background selectors?

An NSTimer is not actually running on a thread. Scheduling a timer to the main thread (actually its NSRunLoop ) will still allow it to handle events and perform other operations before the timer fires.

When the timer fires, the main thread NSRunLoop will invoke the target+selector and then continue waiting for the next event.

I would suggest you replace your code with:

- (void)viewDidLoad {
       [super viewDidLoad];
       // Do any additional setup after loading the view.
       [NSTimer scheduledTimerWithTimeInterval:2
                                        target:self
                                      selector:@selector(targetMethod)
                                      userInfo:nil
                                       repeats:YES];
}

-(void)targetMethod{
         NSLog(@"Timer Called");
}

Note: If targetMethod needs to perform expensive operations, it is recommended that it schedule them to a background thread.

The reason your timer never fires, is that the background thread used by your NSOperationQueue probably doesn't have an NSRunloop . NSTimer instances schedule themselves on the NSRunloop of the thread on which they are created/initialized.

BTW if you ever need to stop (invalidate) an NSTimer - you must do this on the same thread where you created it.

The main thread has its NSRunloop up and running in advance, since all UI (and UI event handling) is done on that runloop. That's why it's easiest to use NSTimer on the main thread.

A possible solution, is to create an NSRunloop for the background thread you're going to use, eg by calling:

[NSRunloop currentRunLoop];

within the block-operation you add to the NSOperationQueue . Documentation says that if there is no runloop for the current thread, currentRunLoop will create one and return it when this is called.

Now another possible issue is, that NSOperationQueue (especially the way you created and initialized it) makes use of undetermined number of threads, can create and dispose threads along the way, and in any way doesn't commit to their lifetime. So... my solution may break.

Instead of using NSOperationQueue , you should create a background thread, create and start its NSRunloop , and then schedule your timer on that runloop.

Another possible solution was already mentioned here - using dispatch_source timer instead of NSTimer , and then - there are better answers than this already.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM