暂停计时器上的dispatch_source_cancel会导致EXC_BAD_INSTRUCTION

Jon*_*ner 18 iphone grand-central-dispatch dispatchertimer ios ios5

我正在尝试取消然后释放暂停的计时器但是当我调用'dispatch_release'时,我立即得到EXC_BAD_INSTRUCTION.

这不是一组有效的计时器吗?

定时器创建和暂停:

@interface SomeClass: NSObject { }
@property (nonatomic, assign) dispatch_source_t             timer;
@end

// Class implementation
@implementation SomeClass

@synthesize timer = _timer;

- (void)startTimer 
{
    dispatch_queue_t globalQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 
                                    0, 0, globalQ); 

    dispatch_time_t startWhen = dispatch_walltime(DISPATCH_TIME_NOW, NSEC_PER_SEC * 1);
    dispatch_source_set_timer(_timer, startWhen, 1 * NSEC_PER_SEC, 5000ull);

    dispatch_source_set_event_handler(_timer, ^{
        // Perform a task 

        // If a particular amount of time has elapsed, kill this timer
        if (timeConstraintReached)
        {
            // Can I suspend this timer within it's own event handler block?
            dispatch_suspend(_timer);
        }
    });

    dispatch_resume(_timer);
}

- (void)resetTimer
{
    dispatch_suspend(_timer);

    dispatch_source_cancel(_timer);

    // dispatch_release causes 
    // 'EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
    dispatch_release(_timer);

    self.timer = nil;    
}
@end
Run Code Online (Sandbox Code Playgroud)

另外,我可以在计时器源的event_handler块中调用dispatch_suspend吗?

任何帮助,将不胜感激.

mat*_*way 30

它崩溃的原因是因为这段代码:

void
_dispatch_source_xref_release(dispatch_source_t ds)
{
    if (slowpath(DISPATCH_OBJECT_SUSPENDED(ds))) {
        // Arguments for and against this assert are within 6705399
        DISPATCH_CLIENT_CRASH("Release of a suspended object");
    }
    _dispatch_wakeup(ds);
    _dispatch_release(ds);
}
Run Code Online (Sandbox Code Playgroud)

因此,您无法释放dispatch_source_t已被暂停的内容.我想你可能只想暂停它resetTimer.

虽然我在文档中找不到他们为什么写这样的内容(并且评论暗示我们将永远看不到的利弊),我所能做的就是参考文档中文档.说:

您可以使用dispatch_suspend和dispatch_resume方法临时暂停和恢复调度源事件的传递.这些方法增加和减少调度对象的挂起计数.因此,在事件传递恢复之前,必须平衡对dispatch_suspend的每个调用以及对dispatch_resume的匹配调用.

虽然这并没有说你不能发布一个已被暂停的调度源,但它确实说你必须平衡每个调用,所以我假设它的某些东西沿着它使用一个调度信号量下的引擎在他们被释放之前保持平衡.这只是我的猜测:-).

至于"我可以在定时器源的event_handler块中调用dispatch_suspend".我很确定你可以,是的,根据以下文档dispatch_suspend:

在完成呼叫时运行的任何块之后发生暂停.