Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't run a timer in GCD block with a dispatch_source_t in iOS application

I want to create a timer in GCD block ( which will fire once every 2 seconds and call a method ) to use it as a background task. But as i see timer fires never. Here is my code:

- (void)startMessaging
{
    BOOL queue = YES;
    dispatch_queue_t _queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_source_t timerSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER,0,0, _queue);
    dispatch_source_set_timer(timerSource, dispatch_walltime(NULL, 0), 2ull * NSEC_PER_SEC,1ull * NSEC_PER_SEC );
    dispatch_source_set_event_handler(timerSource, ^{
        if (queue) {
            [self observeNewMsgs];
        }
    });
    dispatch_resume(timerSource);
}

- (void)observeNewMsgs
{
    NSLog(@"JUST TO TEST");
    // Staff code...
}

So what's a problem with this? How can I fix this?

like image 307
MainstreamDeveloper00 Avatar asked Jan 29 '13 18:01

MainstreamDeveloper00


Video Answer


1 Answers

You have to make your dispatch_source_t a class property or instance variable, so it doesn't fall out of scope (because in ARC, when it falls out of scope, it is released). If you do that, your code will work fine, e.g.:

@interface ViewController ()
@property (nonatomic, strong) dispatch_source_t timerSource;
@property (getter = isObservingMessages) BOOL observingMessages;
@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    [self startMessaging];
}

- (void)startMessaging
{
    self.observingMessages = YES;
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    self.timerSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    dispatch_source_set_timer(self.timerSource, dispatch_walltime(NULL, 0), 2ull * NSEC_PER_SEC, 1ull * NSEC_PER_SEC);
    dispatch_source_set_event_handler(self.timerSource, ^{
        if (self.isObservingMessages) {
            [self observeNewMsgs];
        }
    });
    dispatch_resume(self.timerSource);
}

- (void)observeNewMsgs
{
    NSLog(@"JUST TO TEST");
    // Staff code...
}

@end

Also note, if you wanted the ability to change the value of your BOOL after the background process was initiated, you might want to make that a class property, too, as demonstrated above. I also renamed it to observingMessages to make its purpose more plain.

(It's just stylistic, but I only use the underscore character for class instance variables, so I renamed your _queue variable to be queue.)

like image 100
Rob Avatar answered Sep 21 '22 06:09

Rob