Есть ли простой способ (в Какао / iOS) поставить в очередь вызов метода для запуска один раз в следующем цикле выполнения? - PullRequest
13 голосов
/ 22 сентября 2011

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

Существует ли общий механизм для такого поведения Какао? Можно сказать: «Поставьте в очередь селектор столько раз, сколько хотите, когда пришло время, селектор запустится один раз и очистит очередь.»

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

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

Ответы [ 2 ]

12 голосов
/ 22 сентября 2011

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.

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

6 голосов
/ 22 сентября 2011
[NSObject cancelPreviousPerformRequestsWithTarget:self 
                                         selector:@selector(doTheThing:)
                                           object:someObject];
[self performSelector:@selector(doTheThing:) 
           withObject:someObject 
           afterDelay:0];

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...