Уведомления (Notifications)

Cocoa

Уведомление инкапсулирует информацию о событиях, таких как получения фокуса окном или закрытие сетевого соединения. Объекты, которым необходимо знать об этих событиях, регистрируются в центре уведомлений, и при возникновении зарегистрированного события, центр уведомлений информирует все зарегистрированные объекты об событии.

Стандартный способ передачи информации между объектами - передача сообщений одного объекта вызовом метода другого объекта. Тем не менее, передача сообщений требует, чтобы объект отправки сообщения знал, кто приемник и на какие сообщения он отвечает. Иногда такая тесная связь двух объектов является нежелательной, прежде всего потому, что это заставляет объединить две независимые подсистемы. Для этих случаев вводится модель трансляции ​​объекта сообщенияс уведомлением, которое отправляется на соответствующий объект наблюдатель через объект NSNotificationCenter, или просто центр уведомлений.

NSNotification объект (называемый уведомлением) содержит имя, объект, и необязательный словарь. Имя - тег определяющий уведомление. Объект - любой объект, который будет послан наблюдателю, как правило, в качестве объекта, указывается self. Словарь может содержать дополнительную информацию о событии.

Центры уведомлений

Центр уведомлений управляет получением и отправкой уведомлений. Уведомление заключено в объекте NSNotification. Объекты, желающие получать уведомления, зарегистрированные другими объектами, регистрируются в центре уведомлений. Возможна такая ситуация, когда отправитель и получатель будет один и тотже объект.

Cocoa включает два типа центров уведомлений:

  • NSNotificationCenter - класс управления сообщениями в единственном процессе.
  • NSDistributedNotificationCenter - класс класс управления сообщениями между процессами, на одном компьютере.

NSNotificationCenter

Каждый процесс имеет центр уведомлений по умолчанию, доступ к которому осуществляется с помощью NSNotificationCenter +defaultCenter метода класса. Это центр уведомлений обрабатывает уведомления в рамках одного процесса. Для связи между процессами на одной машине, необходимо использовать распределенный центр уведомлений ("NSDistributedNotificationCenter").

Центр уведомлений обеспечивает наблюдателей уведомлениями синхронно. Иными словами, при отправке уведомления, управление не возвращается на отправителя, пока все наблюдатели не получат и обработают уведомления. Для отправки уведомлений асинхронно следует использовать очередь уведомлений, которая описана в разделе "Очереди уведомлений".

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

NSDistributedNotificationCenter

Каждый процесс имеет по умолчанию, распределенный центр уведомлений, доступ к которому осуществляется с помощью NSDistributedNotificationCenter +defaultCenter метода класса. Распределенный центр уведомлений обрабатывает уведомления, которые могут быть отправлены между процессами на одной машине. Для связи между процессами на разных машинах, используют распределенные объекты.

Посылка распределенных уведомлений является дорогостоящей операцией. Уведомление отправляется на системный сервер, который затем распределяет его по всем процессам, которые имеют объекты, зарегистрированные для распределенных уведомлений. Задержка между объявлением уведомления и прибытием уведомления в другой процесс не ограничен. Фактически, если слишком много уведомлений размещены в текущий момент времени и очередь сервера заполняется, уведомления могут быть сняты.

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

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

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

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

Асинхронная посылка уведомлений

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

Примечание: Если поток прекратился, до того как очередь уведомлений послала уведомление на центр уведомлений, уведомление не посылается.

Очередь уведомлений очищается и ее уведомления посылаются на основе стиля отправки и режима цикла выполнения, указанного в enqueuing методе. Аргумент режима (mode) определяет режим цикла выполнения, в котором очереди будут удалены. Например, если вы укажете NSModalPanelRunLoopMode, уведомления будут отправлены только после выполнения цикла в этом режиме. Если прогон цикла в настоящее время не в данном режиме, уведомления ждут, следующего раза, пока не будет введен требуемый режим. См. "Циклы выполнения в многопоточных приложениях".

Отправка на очередь уведомлений может произойти в одном из трех различных стилей: NSPostASAP, NSPostWhenIdle, и NSPostNow. Эти стили описаны далее.

Отправка как можно скорее

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

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

Отправка во время ожидания

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

Немедленная отправка

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

Слияние уведомлений

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

NSNotificationNoCoalescingНе производить слияние уведомлений в очереди
NSNotificationCoalescingOnNameПроизвести слияние уведомлений с одинаковыми именами
NSNotificationCoalescingOnSenderПроизвести слияние уведомлений с одинаковыми объектами

Вы можете выполнить побитовую OR операцию между NSNotificationCoalescingOnName и NSNotificationCoalescingOnSender константами, чтобы указать сливаться с использованием как имени уведомления, так и объекта уведомления. В следующем примере показано, как можно использовать очередь, чтобы убедиться, что в рамках данного цикла цикла выполнения, все уведомления с именеми 'MyNotificationName' объединились в единое уведомление.

// MyNotificationName определена глобально

NSString *MyNotificationName = @"MyNotification";

id object = <#Объект ассоциированный с уведомлением#>;

NSNotification *myNotification =

        [NSNotification notificationWithName:MyNotificationName object:object]

[[NSNotificationQueue defaultQueue] enqueueNotification:myNotification
        postingStyle:NSPostWhenIdle coalesceMask:NSNotificationCoalescingOnName
        forModes:nil];

Регистрация для получения локальных уведомлений

Вы регистрируете объект, который получит уведомление центра уведомления вызовом метода addObserver:selector:name:object:, с указанием наблюдателя, центр уведомления должен отправить сообщение наблюдателю с совпадающим именем и объектом. Вам не нужно указывать как имя, так и объект. Если указать только объект, наблюдатель будет получать все уведомления с этого объекта. Если указать только имя уведомления, наблюдатель получит уведомление, каждый раз, независимо от объекта, связанного с ним.

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

Если вы решите, что наблюдателю больше не нужно получать уведомления (например, если наблюдатель в настоящее время освобожден), вы можете удалить наблюдателя из списка центра уведомлений наблюдателей методами removeObserver: или removeObserver:name:object:.

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

[[NSNotificationCenter defaultCenter] addObserver:self
    selector:@selector(aWindowBecameMain:)
    name:NSWindowDidBecomeMainNotification object:nil];

Передавая nil в качестве объекта наблюдения, объект клиента (self) получает уведомление, когда любой объект посылает NSWindowDidBecomeMainNotification уведомление.

Когда окно становится основным, оно посылает NSWindowDidBecomeMainNotification на центра уведомлений. Центр уведомлений уведомляет всех наблюдателей, которые заинтересованы в уведомлении, вызвав метод, который они указали в аргументе selector метода addObserver:selector:name:object:. В нашем примере наблюдателя, селектором является aWindowBecameMain. aWindowBecameMain: метод может иметь следующие реализации:

- (void)aWindowBecameMain:(NSNotification *)notification 
{
    NSWindow *theWindow = [notification object];

    MyDocument = (MyDocument *)[[theWindow windowController] document];

    // Получить информацию о документе и обновить панель.
}

NSWindow объектам не нужно ничего знать о ваших панелях инспектора.

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

Объект регистрируется, тобы получать уведомления, отправив addObserver:selector:name:object:suspensionBehavior: метод объекта NSDistributedNotificationCenter, с указанием сообщения, которое необходимо отправить уведомлению, название уведомления, которое он хочет получать, строку идентификатор, чтобы соответствовать (аргументу object), и поведение, что следует делать, если уведомление о доставке приостановлено.

Поскольку размещение объекта и наблюдателя могут быть в разных процессах, уведомление не может содержать указатели на произвольные объекты. Таким образом, класс NSDistributedNotificationCenter требует от уведомления использовать объект NSString в качестве аргумента object. Уведомление соответственно осуществляется на основе данной строки, а не указателя на объект.

Когда процесс уже не заинтересован в получении уведомлений немедленно, он может приостановить отправку уведомлений. Это часто делается, когда приложение скрыто, или помещено в фоновый режим. (NSApplication объект автоматически приостанавливает поставки, когда приложение не активно). suspensionBehavior аргумент в addObserver методе определяет, как прибывающие уведомления должны быть обработаны в то время как поставки приостановлены. Есть четыре различных типа поведения, каждый полезен при различных обстоятельствах.

suspensionBehaviorОписание
NSNotificationSuspensionBehaviorDropСервер не использует очередь уведомлений с данным именем и объектом, пока не получит setSuspended:NO сообщение.
NSNotificationSuspensionBehaviorCoalesceСервер очередей оставит только последнее уведомление с указанными именем и объектом; ранние уведомления удаляются. Распространяется на методы, для которых подвешенное поведение не является явным аргументом, NSNotificationSuspensionBehaviorCoalesce является значением по умолчанию.
NSNotificationSuspensionBehaviorHoldСервер держит все соответствующие уведомления, пока очередь не будет заполнена (размер очереди определяется сервером), после чего сервер может очистить очередь уведомлений.
NSNotificationSuspensionBehaviorDeliverImmediatelyСервер поставляет уведомления для этой регистрации независимо от того, получено-ли setSuspended:YES сообщение. Когда уведомление с этим подвешенным поведением совпадают, оно имеет эффект первой очистки любой очереди уведомлений.

Вы приостанавливаете отправку уведомлений, посылая setSuspended:YES распределенному центру уведомлений. В то время как уведомления приостановлены, сервер уведомлений обрабатывает уведомления, предназначенные для процесса, который приостановил доставку уведомлений в соответствии с типом поведения подвески указанных наблюдателей, когда они зарегистрированы для получения уведомлений. Когда процесс возобновляет доставку уведомлений, все очереди уведомлений немедленно доставляются. В приложениях, использующих Application Kit, NSApplication объект автоматически приостанавливает доставку уведомлений, когда приложение не активно.

Неактивное состояние может быть отменено и посылающий может разместить уведомление с немедленной доставкой всем получателям вызовом NSDistributedNotificationCenter postNotificationName:object:userInfo:deliverImmediately: метода с значением аргумента deliverImmediately YES.

Отмена регистрации наблюдателей

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

[[NSNotificationCenter defaultCenter] removeObserver:self];

Для наблюдателей распределенных уведомлений следует отправить:

[[NSDistributedNotificationCenter defaultCenter] removeObserver:self];

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

Посылка локальных уведомлений

Вы можете создать объект уведомления с помощью notificationWithName:object: или notificationWithName:object:userInfo:. Затем разместить объект уведомления на центре уведомлений с помощью postNotification: метода экземпляра. NSNotification объекты являются неизменными.

Однако, обычно, нет необходимости создавать свои собственные уведомления непосредственно. Методы postNotificationName:object: и postNotificationName:object:userInfo: класса NSNotificationCenter позволяют удобно посылать уведомления без предварительного его создания.

В любом случае, вы обычно размещаете уведомление в центре уведомлений процесса по умолчанию . Вы получаете по объект умолчанию с помощью метода класса defaultCenter.

Пример отправки локального уведомления:

[[NSNotificationCenter defaultCenter]

    postNotificationName:@"NavigationStart" object:self];

Центр уведомлений затем определяет, какие объекты (если таковые имеются) заинтересованы в этих уведомлениях и уведомляет их.

Если есть другие объекты, представляющие интерес для наблюдателя (кроме названия уведомления и наблюдаемого объекта), поместите их в дополнительный словарь уведомления или используйте postNotificationName:object:userInfo:.

Посылка распределенных уведомлений

Отправка распределенных уведомлений является такой же, как отправка локальных уведомлений. Вы можете создать NSNotification объект вручную и отправить с помощью postNotification: или использовать один из удобных методов NSDistributedNotificationCenter. Единственное отличие заключается в том, что объект уведомления должен быть строковым объектом и дополнительный пользовательский словарь может содержать только список свойств объектов, таких как NSString и NSNumber.

 
 
homeЗаметили ошибкукарта сайта 
   Made on a Mac