GCD计时器频繁崩溃

时间:2015-07-30 21:52:53

标签: ios objective-c block grand-central-dispatch

我用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);

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

1 个答案:

答案 0 :(得分:0)

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

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

要修复,请在创建后立即检查strongSelf。如果它是零,只需返回。

我还注意到dealloc中没有MyTimer方法。我怀疑保留了恢复的GCD计时器,因此当您MyTimer被释放时,它不会被无效/释放。您应该添加一个dealloc [self invalidate]