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

Есть ли простой способ (в Cocoa/iOS) поставить очередь вызова метода для запуска один раз в следующем цикле запуска?

UIView имеет метод setNeedsDisplay, который можно вызвать несколько раз в пределах одного цикла событий, безопасно, зная, что работа по перерисовке произойдет в ближайшее время, и только один раз.

Существует ли общий механизм такого поведения Cocoa? Способ сказать: "Остановите селектор столько раз, сколько захотите, когда это время, селектор будет запускаться один раз и очищать очередь".

Я знаю, что смогу сделать это с каким-то отслеживанием состояния в моей цели или с NSOperationQueue. Мне просто интересно, есть ли легкий подход, который я пропустил.

(Конечно, ответ может быть "Нет".)

4b9b3361

Ответ 1

setNeedsDisplay не является хорошим примером того, что вы описываете, поскольку он действительно запускается каждый раз, когда вы его вызываете. Он просто устанавливает флаг. Но вопрос хороший.

Одним из решений является использование NSNotificationQueue с помощью NSNotificationCoalescingOnName.

Другое решение - построить батут, чтобы выполнить объединение. У меня нет хороших ссылок на блоги для батутов, но вот пример одного (LSTrampoline). Это не так сложно построить, если вы хотите объединить сообщения в течение определенного периода времени. Я однажды построил батут с forwardInvocation:, похожим на это:

- (void)forwardInvocation:(NSInvocation *)invocation {
  [invocation setTarget:self.target];
  [invocation retainArguments];
  [self.timer invalidate];
  self.timer = [NSTimer scheduledTimerWithTimeInterval:self.timeout invocation:invocation repeats:NO];
}

Это фактически объединяет все сообщения с объектом в течение периода времени (а не только для сопоставления сообщений). Это все, что мне нужно для конкретной проблемы. Но вы можете расширить это, чтобы отслеживать, какие селекторы объединяются, и проверьте свои призывы, чтобы убедиться, что они соответствуют "достаточно".

Чтобы запустить этот цикл в следующем цикле событий, установите время ожидания равным 0.

Я сохраняю смысл в блоге о батутах. Требуемый шиллинг: My предстоящая книга охватывает батуты в главе 4 и главе 20.

Ответ 2

[NSObject cancelPreviousPerformRequestsWithTarget:self 
                                         selector:@selector(doTheThing:)
                                           object:someObject];
[self performSelector:@selector(doTheThing:) 
           withObject:someObject 
           afterDelay:0];

Это не так, как это делает UIView, потому что setNeedsDisplay просто устанавливает флаг, а внутренний механизм UIView обязательно вызывает drawRect: после настройки среды рисования, но это общий способ и не требует специального отслеживания состояния в вашем классе.