Очереди уведомления

NSNotificationQueue объекты, или просто, очереди уведомления, действуют как буферы для центров уведомления (экземпляры NSNotificationCenter). NSNotificationQueue класс вносит две важных функции в механизм уведомления Фундэйшна Кита: объединение уведомлений и асинхронная регистрация.

Основы очереди уведомления

Используя NSNotificationCenter postNotification: метод и его варианты, можно отправить уведомление центру уведомления. Однако вызов метода синхронен: прежде чем объект регистрации может возобновить свой поток выполнения, он должен ожидать, пока центр уведомления не диспетчеризирует уведомление всем наблюдателям и возвратам. Очередь уведомления, с другой стороны, поддерживает уведомления (экземпляры NSNotification) обычно в порядке Метода «первым пришел - первым вышел» (FIFO). Когда уведомление повышается до передней стороны очереди, очередь отправляет его на центр уведомления, поочередно диспетчеризирующий уведомление всем объектам, зарегистрированным как наблюдатели.

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

Регистрация уведомлений асинхронно

С NSNotificationQueue enqueueNotification:postingStyle: и enqueueNotification:postingStyle:coalesceMask:forModes: методы, можно отправить уведомление асинхронно текущему потоку путем помещения его в очередь. Эти методы сразу возвращаются к объекту вызова после помещения уведомления в очереди.

Очередь уведомления освобождена, и ее уведомления отправляются на основе стиля регистрации и выполненного режима цикла, указанного в методе постановки в очередь. Параметр режима указывает режим цикла выполнения, в котором будет освобождена очередь. Например, если Вы указываете NSModalPanelRunLoopMode, уведомления будут отправлены только, когда цикл выполнения будет в этом режиме. Если цикл выполнения в настоящее время не находится в этом режиме, уведомления ожидают до следующего раза, когда к режиму переходят. Посмотрите Режимы Цикла Выполнения для получения дополнительной информации.

Регистрация на очередь уведомления может произойти в одном из трех различных стилей: NSPostASAP, NSPostWhenIdle, и NSPostNow. Эти стили описаны в следующих разделах.

Регистрация как можно скорее

Любое уведомление, поставленное в очередь с NSPostASAP стиль отправляется на центр уведомления, когда текущая итерация цикла выполнения завершается, предполагая, что текущий режим цикла выполнения соответствует требуемый режим. (Если требуемые и текущие режимы отличаются, уведомление отправляется, когда переходят к требуемому режиму.), Поскольку цикл выполнения может сделать многократные выноски во время каждой итерации, уведомление может или не может быть поставлено, как только текущие выходы выноски и управление возвращаются к циклу выполнения. Другие выноски могут иметь место сначала, такие как таймер или исходное увольнение или другие асинхронные поставляемые уведомления.

Вы обычно используете NSPostASAP отправляя стиль для дорогого ресурса, такого как сервер дисплея. Когда много клиентов привлекают буфер окна во время выноски от цикла выполнения, дорого сбросить буфер к серверу дисплея после каждой работы получения. В этой ситуации, каждом draw... метод ставит в очередь некоторое уведомление, такое как «FlushTheServer» с объединением на имени и указанном объекте и со стилем регистрации NSPostASAP. В результате только одно из тех уведомлений диспетчеризируется в конце цикла выполнения, и буфер окна сбрасывается только один раз.

Регистрация, когда неактивный

Уведомление, поставленное в очередь с NSPostWhenIdle стиль отправляется только, когда цикл выполнения находится в состоянии ожидания. В этом состоянии нет ничего в каналах ввода цикла выполнения, быть им таймеры или другие асинхронные события. Типичный пример организации очередей с NSPostWhenIdle стиль происходит, когда пользователь вводит текст, и программа выводит на экран размер текста в байтах где-нибудь. Это было бы очень дорого (и не очень полезно) обновить размер текстового поля после каждого символа пользовательские типы, особенно если пользователь вводит быстро. В этом случае программа ставит в очередь уведомление, такое как «ChangeTheDisplayedSize», с объединением включенного и стиль регистрации NSPostWhenIdle после того, как каждый символ вводится. Когда пользователь прекращает вводить, единственное уведомление «ChangeTheDisplayedSize» в очереди (вследствие объединения) отправляется, когда цикл выполнения вводит свое состояние ожидания, и дисплей обновляется. Обратите внимание на то, что цикл выполнения, собирающийся выйти (который происходит, когда все каналы ввода истекли) не находится в состоянии ожидания и таким образом не отправит уведомление.

Регистрация сразу

Уведомление, поставленное в очередь с NSPostNow сразу отправляется после объединения к центру уведомления. Вы ставите уведомление в очередь с NSPostNow (или отправьте один с postNotification:) когда Вы не требуете асинхронного поведения вызова. Для многих ситуаций с программированием синхронное поведение не только допустимо, но и желательно: Вы хотите, чтобы центр уведомления возвратился после диспетчеризации, таким образом, можно быть уверены, что объекты наблюдения получили и обработали уведомление. Конечно, необходимо использовать enqueueNotification... с NSPostNow вместо того, чтобы использовать postNotification: когда существуют подобные уведомления в очереди, которую Вы хотите удалить посредством объединения.

Объединение уведомлений

В некоторых ситуациях можно хотеть отправить уведомление, если данное событие имеет место, по крайней мере, один раз, но Вы хотите отправить не больше, чем одно уведомление, даже если событие имеет место многократно. Например, в приложении, получающем данные в дискретных пакетах, по получении пакета, можно хотеть отправить уведомление, чтобы показать, что должны быть обработаны данные. Если многократные пакеты поступают в данном периоде времени, однако, Вы не хотите отправлять многократные уведомления. Кроме того, объект, отправляющий эти уведомления, может не иметь никакого способа знать, прибывает ли больше пакетов или нет, вызывают ли метод регистрации в цикле или нет.

В некоторых ситуациях может быть возможно просто установить булев флаг (ли переменная экземпляра объекта или глобальной переменной), чтобы обозначить, что событие имело место и подавить регистрацию дальнейших уведомлений, пока не очищен флаг. Если это не возможно, однако, в этой ситуации Вы не можете непосредственно использовать NSNotificationCenter так как его поведение синхронно — уведомления отправляются перед возвратом, таким образом нет никакой возможности для "игнорирования” двойных уведомлений; кроме того, NSNotificationCenter экземпляр не имеет никакого способа знать, прибывает ли больше уведомлений или нет.

Вместо того, чтобы отправлять уведомление центру уведомления, поэтому, можно добавить уведомление NSNotificationQueue экземпляр, указывающий надлежащую опцию для объединения. Объединение является процессом, удаляющим из очереди уведомления, которые подобны в некотором роде уведомлению, поставленному в очередь ранее. Вы указываете критерии подобия путем указания один или больше следующих констант в третьем параметре enqueueNotification:postingStyle:coalesceMask:forModes: метод.

NSNotificationNoCoalescingНе объединяйте уведомления в очереди.
NSNotificationCoalescingOnNameОбъедините уведомления с тем же именем.
NSNotificationCoalescingOnSenderОбъедините уведомления с тем же объектом.

Можно выполнить работу битового «ИЛИ» с NSNotificationCoalescingOnName и NSNotificationCoalescingOnSender константы для указания объединения с помощью и имени уведомления и объекта уведомления. Следующий пример иллюстрирует, как Вы могли бы использовать очередь, чтобы гарантировать что, в данном цикле цикла событий, все названные уведомления MyNotificationName объединяются в единственное уведомление.

// MyNotificationName defined globally
NSString *MyNotificationName = @"MyNotification";
 
id object = <#The object associated with the notification#>;
NSNotification *myNotification =
        [NSNotification notificationWithName:MyNotificationName object:object]
[[NSNotificationQueue defaultQueue]
        enqueueNotification:myNotification
        postingStyle:NSPostWhenIdle
        coalesceMask:NSNotificationCoalescingOnName
        forModes:nil];