无法在iOS应用程序中使用dispatch_source_t在GCD块中运行计时器

Mai*_*r00 11 timer objective-c grand-central-dispatch ios

我想在GCD块中创建一个计时器(每2秒触发一次并调用一个方法)将其用作后台任务.但是,我认为计时器永远不会发火.这是我的代码:

- (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...
}
Run Code Online (Sandbox Code Playgroud)

那么这有什么问题呢?我怎样才能解决这个问题?

Rob*_*Rob 30

您必须创建dispatch_source_t一个类属性或实例变量,因此它不会超出范围(因为在ARC中,当它超出范围时,它将被释放).如果你这样做,你的代码将正常工作,例如:

@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
Run Code Online (Sandbox Code Playgroud)

另请注意,如果您希望能够BOOL在启动后台进程后更改您的值,那么您可能也希望将其设为类属性,如上所示.我还将其重命名observingMessages为使其目的更加明确.

(这只是风格,但我只使用下划线字符作为类实例变量,因此我将您的_queue变量重命名为queue.)

  • 如果你的目标是10.8之前的OS X版本或6之前的iOS版本,你也会得到这个错误,因为它早于GCD类型的对象处理,因此需要手动`dispatch_retain`和`dispatch_release`. (2认同)