Отмена предыдущего вызова dispatch_async

Я реализую механизм отслеживания окна A, следуя позиции окна B. Окно B отправляет события своей позиции, а окно B реагирует на эти события, вызывая setWindowProperties:

void setWindowProperties(bool topMost, bool visible, 
                         CGWindowID parentWindow, CGWindowID aboveWindow, 
                         NSRect windowFrame, NSRect viewFrame, bool isAbove)
{
    dispatch_async(dispatch_get_main_queue(), ^{
        setWindowPropertiesImpl(topMost, visible, parentWindow, aboveWindow, windowFrame, viewFrame, isAbove);
    });
}

Но из-за слишком большого количества событий, посылаемых окном B, я получаю эффект "отслеживания змей". Я хочу преодолеть это, реагируя только на последнее событие позиции, то есть отменив все предыдущие вызовы:

dispatch_async(dispatch_get_main_queue(), ^{
    setWindowPropertiesImpl(topMost, visible, parentWindow, aboveWindow, windowFrame, viewFrame, isAbove);
});

И в результате, оставляя в очереди только последнее событие позиции - единственное, что имеет значение.

Мой вопрос: есть ли способ отменить все предыдущие звонки на dispatch_async?

2 ответа

Да, задачи отправки теперь можно отменять, но когда есть события, которые приходят быстрее, чем основная очередь может их обработать, иногда полезно использовать источник отправки. Конкретно DISPATCH_SOURCE_TYPE_DATA_ADD источник данных.

// create source (and save this reference somewhere so it doesn't get released on you)

dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, dispatch_get_main_queue());

// specify what you want the event handler to do

dispatch_source_set_event_handler(source, ^{
    // whatever you want to do 
});

// start the dispatch source

dispatch_resume(source);

Затем, когда вы хотите, чтобы вызвать это, а не делать dispatch_async, ты бы:

dispatch_source_merge_data(source, 1);

Понятно, что это означает, что обработчик событий должен извлекать данные из другого окна, а не выдвигать их, но, надеюсь, это иллюстрирует основную идею.


Для получения дополнительной информации см. Видео шаблоны асинхронного проектирования WWDC 2012 с блоками, GCD и XPC. В частности, см. Шаблон проектирования 8 "Асинхронное обновление состояния" в последней части видео.

Вы не можете отменить операцию, поставленную в очередь в очереди отправки.

Очереди GCD не могут отменить блок, как только он запланирован. Архитектура очень сильно "огонь и забудь".

Вместо GCD вы можете использовать NSOperationQueue, который также может выполнять асинхронное выполнение, затем вы можете отменить.

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