GCD 计时器经常崩溃

GCD Timer crashes with frequently

我用 GCD dispatch_source 创建了一个非常简单的计时器,我经常收到这种奇怪的崩溃。代码对我来说看起来很好。如果有人能解释这背后的原因,我将非常高兴。

@interface MyTimer ()

@property (nonatomic, strong, readonly) dispatch_queue_t queue;
@property (nonatomic, readonly) NSTimeInterval timeOutDuration;
@property (nonatomic, copy, readonly) dispatch_block_t callback;
@property (nonatomic, strong) dispatch_group_t group;

@property (nonatomic, strong) dispatch_source_t timer;

@end


@implementation MyTimer

- (instancetype)initWithQueue:(dispatch_queue_t)queue
                     callback:(dispatch_block_t)callback
              timeOutDuration:(NSTimeInterval)interval
{
    NSAssert(queue, @"queue must not be nil");
    NSAssert(callback, @"callback must not be nil");

    if (self = [super init]) {
        _queue = queue;
        _callback = [callback copy];
        _timeOutDuration = interval;
        _group = dispatch_group_create();
        [self setupTimer];
    }
    return self;
}

- (void)setupTimer
{
    self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.queue);
    dispatch_source_set_timer(self.timer, dispatch_time(DISPATCH_TIME_NOW, self.timeOutDuration * NSEC_PER_SEC), 0, 0);

    __weak typeof(self) weakSelf = self;
    dispatch_source_set_event_handler(self.timer, ^{
        __strong typeof(self) strongSelf = weakSelf;
        // crashes on the next line
        dispatch_group_async(strongSelf.group, dispatch_get_main_queue(), strongSelf.callback);
        dispatch_group_async(strongSelf.group, strongSelf.queue, ^{
            [strongSelf invalidate];
        });
    });
}

- (void)fire
{
    dispatch_resume(self.timer);
}

- (void)invalidate
{
    if (self.timer) {
        dispatch_source_cancel(self.timer);
        _timer = nil;
        _callback = nil;
    }
} 
@end

它通常在这一行崩溃,

  dispatch_group_async(strongSelf.group, dispatch_get_main_queue(), strongSelf.callback);

崩溃并非总是发生,而是经常发生。我无法理解崩溃背后的逻辑。

假设计时器将块排队等待执行。当块挂起时,MyTimer 对象的保留计数变为零,并且 MyTimer 被释放。然后弱引用weakSelf设置为nil.

然后块执行。它从 weakSelf 创建 strongSelf。由于 weakSelf 现在为零,因此 strongSelf 也为零。所以 strongSelf.groupstrongSelf.callback 都是 return nil,你将这些 nils 传递给 dispatch_group_async。糟糕的节目!没有饼干!

要修复,请在创建后立即检查 strongSelf。如果为零,则 return.

我还注意到您在 MyTimer 中没有 dealloc 方法。我怀疑恢复的 GCD 定时器被保留,所以当你的 MyTimer 被释放时它不会是 invalidated/released。您可能应该添加一个 dealloc 来执行 [self invalidate].