Подтвердить что ты не робот

Dispatch_source_cancel на приостановленном таймере вызывает EXC_BAD_INSTRUCTION

Я пытаюсь отменить, а затем отпустить приостановленный таймер, но когда я вызываю "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 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

Кроме того, могу ли я вызвать dispatch_suspend в блоке event_handler источника таймера?

Любая помощь будет оценена.

4b9b3361

Ответ 1

Причина его сбоя связана с этот код:

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);
}

Итак, вы не можете отпустить dispatch_source_t, который был приостановлен. Вероятно, вы хотите просто не приостановить его в resetTimer, я думаю.

Пока я не могу найти что-либо в документах, почему они так написаны (и комментарий ссылается на плюсы и минусы в радаре, которые мы никогда не увидим), все, что я могу сделать, это обратиться к docs где он говорит:

Вы можете приостановить и возобновить доставку событий источника отправки временно используя методы dispatch_suspend и dispatch_resume. Эти методы увеличивают и уменьшают количество приостановленных отправка объект. В результате вы должны сбалансировать каждый dispatch_suspend с соответствующим вызовом dispatch_resume до события доставка возобновляется.

В то время как это не говорит, что вы не можете освободить источник отправки, который был приостановлен, он говорит, что вам нужно балансировать каждый вызов, поэтому я предполагаю, что это что-то в соответствии с его использованием с помощью семафора отправки под управлением, кадр, который должен быть сбалансирован, прежде чем они могут быть выпущены. Это только моя догадка, хотя: -).

Что касается "могу ли я вызвать dispatch_suspend в блоке event_handler источника таймера". Я уверен, что вы можете, да, согласно документам для dispatch_suspend:

Приостановка происходит после завершения любых блоков, запущенных во время вызова.