Не удается запустить таймер в блоке GCD с dispatch_source_t в приложении 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...
}

Так в чем проблема с этим? Как я могу это исправить?

1 ответ

Решение

Вы должны сделать свой 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

Также обратите внимание, если вы хотели возможность изменить значение вашего BOOL после того, как был запущен фоновый процесс, вы можете захотеть сделать это свойство класса тоже, как показано выше. Я также переименовал его в observingMessages чтобы сделать его цель более понятной.

(Это просто стилистика, но я использую символ подчеркивания только для переменных экземпляра класса, поэтому я переименовал ваш _queue переменная быть queue.)

Другие вопросы по тегам