码迷,mamicode.com
首页 > 其他好文 > 详细

Notification Centers 通知中心

时间:2015-06-02 23:31:53      阅读:502      评论:0      收藏:0      [点我收藏+]

标签:移动互联网   ios开发   通知中心   objective-c   

Notification Centers
通知中心

notification center manages the sending and receiving of notifications. It notifies all observers of notifications meeting specific criteria. The notification information is encapsulated in NSNotification objects. Client objects register themselves with the notification center as observers of specific notifications posted by other objects. When an event occurs, an object posts an appropriate notification to the notification center. (See “Posting a Notification” for more on posting notifications.) The notification center dispatches a message to each registered observer, passing the notification as the sole argument. It is possible for the posting object and the observing object to be the same.

Cocoa includes two types of notification centers:

  • The NSNotificationCenter class manages notifications within a single process.

  • The NSDistributedNotificationCenter class manages notifications across multiple processes on a single computer.

    一个通知中心管理着通知的发送和接收。它会通知所有满足指定规则的观察者。通知的信息被封装在NSNotification对象中。客户对象将自身注册到通知中心作为从其他对象发送来的具体通知的观察者。当一个事件发生时,对象将发布一个合适的通知到通知中心(查看 “Posting a Notification”了解更多)。通知中心分派一个消息到每一个被注册的观察者,并作为唯一的参数传递通知。存在发送者对象和观察者对象是同一个对象的可能。
    Cocoa包括两种类型的通知中心:
  • NSNotificationCenter类管理单进程内的通知。
  • NSDistributedNotificationCenter类在一台计算中通过多进程管理通知。
NSNotificationCenter
通知中心

Each process has a default notification center that you access with the NSNotificationCenter +defaultCenter class method. This notification center handles notifications within a single process. For communication between processes on the same machine, use a distributed notification center (see “NSDistributedNotificationCenter”).

A notification center delivers notifications to observers synchronously. In other words, when posting a notification, control does not return to the poster until all observers have received and processed the notification. To send notifications asynchronously use a notification queue, which is described in “Notification Queues.”

In a multithreaded application, notifications are always delivered in the thread in which the notification was posted, which may not be the same thread in which an observer registered itself.
每一个进程都有一个默认的通知中心,你可以使用NSNotificationCenter类的+defaultCenter类方法进行访问。这个通知中心控制着这个进程内的通知。你可以使用分布式通知中心实现不同进程间的通信 (see “NSDistributedNotificationCenter”)。
通知中心传送通知到观察者是同步的,也就是说,当通知中心发送一个通知,所有的观察者都已接收并处理了通知后控制权才会返回。要同步地发送通知,需要使用通知队列,关于通知队列的描述详见“Notification Queues.”
NSDistributedNotificationCenter
分布式通知中心

Each process has a default distributed notification center that you access with the NSDistributedNotificationCenter +defaultCenter class method. This distributed notification center handles notifications that can be sent between processes on a single machine. For communication between processes on different machines, use distributed objects (see Distributed Objects Programming Topics).

每一个进程都有一个默认的分布式通知中心,你可以使用NSDistributedNotificationCenter类的+defaultCenter类方法进行访问。这个通知中心控制着同一台机器上可以在不同进程间发送的通知。在不同机器的不同进程间通信,使用分布式对象。

Posting a distributed notification is an expensive operation. The notification gets sent to a systemwide server that then distributes it to all the processes that have objects registered for distributed notifications. The latency between posting the notification and the notification’s arrival in another process is unbounded. In fact, if too many notifications are being posted and the server’s queue fills up, notifications can be dropped.

发布一个分布式通知是一个开销很大的操作。通知被发送到系统服务,然后再被系统服务分发到所有注册了分布式通知的对象的进程。发布通知与通知到达另外一个进程之间的潜在因素是不受控的。实际上,如果发布了太多的通知导致服务队列被填满,通知会被删除。

Distributed notifications are delivered via a process’s run loop. A process must be running a run loop in one of the “common” modes, such as NSDefaultRunLoopMode, to receive a distributed notification. If the receiving process is multithreaded, do not depend on the notification arriving on the main thread. The notification is usually delivered to the main thread’s run loop, but other threads could also receive the notification.
分布式通知通过进程的运行循环进行传送,进程必须是运行在一个"common"模式下的运行循环,例如 NSDefaultRunLoopMode,去接收分布式通知。如果接收进程是多线程的,不依赖于到达主线程的通知。通知通常被传送到主线程的运行循环,但是其他的线程也可以接收这个通知。

Whereas a regular notification center allows any object to be observed, a distributed notification center is restricted to observing a string object. Because the posting object and the observer may be in different processes, notifications cannot contain pointers to arbitrary objects. Therefore, a distributed notification center requires notifications to use a string as the notification object. Notification matching is done based on this string, rather than an object pointer.
然而,一个标准的通知中心允许被任何对象注册,分布式通知中心被限制为观察一个字符串对象。因为发布对象和观察者可能在不同的进程中,通知不能包含指向任意对象的指针。因此,一个分布式通知中心要求通知使用一个字符串作为通知对象。相比使用对象指针,通知能更好的匹配这个字符串。

Notification Queues
通知队列

NSNotificationQueue objects, or simply, notification queues, act as buffers for notification centers (instances of NSNotificationCenter). The NSNotificationQueue class contributes two important features to the Foundation Kit’s notification mechanism: the coalescing of notifications and asynchronous posting. 
通知队列对象,或者简单说,通知队列,扮演着通知中心(NSNotificationCenter的实例)缓冲区的角色 NSNotificationQueue 类为Foundation Kit的通知机制贡献了两个重要的功能:聚合通知和异步发布通知。

Notification Queue Basics
通知队列基础

Using the NSNotificationCenter’s postNotification: method and its variants, you can post a notification to a notification center. However, the invocation of the method is synchronous: before the posting object can resume its thread of execution, it must wait until the notification center dispatches the notification to all observers and returns. A notification queue, on the other hand, maintains notifications (instances of NSNotification) generally in a First In First Out (FIFO) order. When a notification rises to the front of the queue, the queue posts it to the notification center, which in turn dispatches the notification to all objects registered as observers.

Every thread has a default notification queue, which is associated with the default notification center for the process. You can createyour own notification queues and have multiple queues per center and thread.
每一个线程都有一个默认的通知队列跟进程默认的通知中心关联在一起,你可以创建自己的通知队列,每一个通知中心和线程可以拥有多个队列。
Posting Notifications Asynchronously
异步的发送通知

With NSNotificationQueue’s enqueueNotification:postingStyle: and enqueueNotification:postingStyle:coalesceMask:forModes: methods, you can post a notification asynchronously to the current thread by putting it in a queue. These methods immediately return to the invoking object after putting the notification in the queue.

Note: When the thread where a notification is enqueued terminates before the notification queue posts the notification to its notification center, the notification is not posted. See “Delivering Notifications To Particular Threads” to learn how to post a notification to a different thread.
线程在通知队列发布通知到它的通知中心前结束,这个通知将不会发布。查看 “Delivering Notifications To Particular Threads” 学习如何发送通知到不同的线程。
The notification queue is emptied and its notifications posted based on the posting style and run loop mode specified in the enqueuing method. The mode argument specifies the run loop mode in which the queue will be emptied. For example, if you specify NSModalPanelRunLoopMode, the notifications will be posted only when the run loop is in this mode. If the run loop is not currently in this mode, the notifications wait until the next time that mode is entered. See “Run Loop Modes” in Threading Programming Guide for more information.
通知队列被置空,它的通知发布基于发布格式和在队列方法中规定的运行循环模式。模式参数指定了将会被置空的那个队列所在的线程的运行循环模式。例如,如果你指定NSModalPanelRunLoopMode,通知就只会在运行循环处于该模式时被发布。如果运行循环当前不是处于该模式,通知就需要等到运行循环下一次进入该模式才能被发布。查看Threading Programming Guide中的“Run Loop Modes” 了解更多信息。
Posting to a notification queue can occur in one of three different styles: NSPostASAPNSPostWhenIdle, and NSPostNow. These styles are described in the following sections. 
通知队列的发布可以选择以下三种不同的格式之一:NSPostASAPNSPostWhenIdle, 和 NSPostNow.这些格式在接下来的段落中进行描述。
Posting As Soon As Possible
尽快发布
Any notification queued with the NSPostASAP style is posted to the notification center when the current iteration of the run loop completes, assuming the current run loop mode matches the requested mode. (If the requested and current modes are different, the notification is posted when the requested mode is entered.) Because the run loop can make multiple callouts during each iteration, the notification may or may not get delivered as soon as the current callout exits and control returns to the run loop. Other callouts may take place first, such as a timer or source firing or other asynchronous notifications being delivered.
假设当前的运行循环与要求的运行循环是匹配的,那么任何NSPostASAP格式的通知会在运行循环当前迭代完成时被发布到统治中心(如果要求的运行循环与当面运行循环不同,通知会在运行循环下一次进入该模式时被发布)。因为运行循环在每一次迭代中可以处理多个callout,通知可能不会在当前callout退出后立即传送并将控制返回到运行循环。其他的callout可能被优先处理,例如时间或者资源占用,或者其他异步通知正在传送。
You typically use the NSPostASAP posting style for an expensive resource, such as the display server. When many clients draw on the window buffer during a callout from the run loop, it is expensive to flush the buffer to the display server after every draw operation. In this situation, each draw... method enqueues some notification such as “FlushTheServer” with coalescing on name and object specified and with a posting style of NSPostASAP. As a result, only one of those notifications is dispatched at the end of the run loop and the window buffer is flushed only once.
Posting When Idle
空闲时发布

A notification queued with the NSPostWhenIdle style is posted only when the run loop is in a wait state. In this state, there’s nothing in the run loop’s input channels, be it timers or other asynchronous events. A typical example of queuing with the NSPostWhenIdle style occurs when the user types text, and the program displays the size of the text in bytes somewhere. It would be very expensive (and not very useful) to update the text field size after each character the user types, especially if the user types quickly. In this case, the program queues a notification, such as “ChangeTheDisplayedSize,” with coalescing turned on and a posting style of NSPostWhenIdle after each character typed. When the user stops typing, the single “ChangeTheDisplayedSize” notification in the queue (due to coalescing) is posted when the run loop enters its wait state and the display is updated. Note that a run loop that is about to exit (which occurs when all of the input channels have expired) is not in a wait state and thus will not post a notification.

Posting Immediately
立即发布

A notification queued with NSPostNow is posted immediately after coalescing to the notification center. You queue a notification with NSPostNow (or post one with postNotification:) when you do not require asynchronous calling behavior. For many programming situations, synchronous behavior is not only allowable but desirable: You want the notification center to return after dispatching so you can be sure that observing objects have received and processed the notification. Of course, you should use enqueueNotification... with NSPostNow rather than use postNotification: when there are similar notifications in the queue that you want to remove through coalescing.

Coalescing Notifications
聚合通知
In some situations, you may want to post a notification if a given event occurs at least once, but you want to post no more than one notification even if the event occurs multiple times. For example, in an application that receives data in discrete packets, upon receipt of a packet you may wish to post a notification to signify that the data needs to be processed. If multiple packets arrive within a given time period, however, you do not want to post multiple notifications. Moreover, the object that posts these notifications may not have any way of knowing whether more packets are coming or not, whether the posting method is called in a loop or not.
在某些情况下,你可能希望在一个给定的事件发生时至少发送一次通知,但是你希望发送不止一条通知,即使这个事件多次发生。例如,在应用中接收分包传输的数据,根据接收到的数据包你可能希望发布一个通知表示数据需要被执行。如果多个数据包在给定的时间段内到达,你不希望发布多个通知。但是情况不止是这样,发送通知的对象可能并没有任何方式知道是否还有更多的数据包发送过来,发布方法是否在一个循环中调用。
In some situations it may be possible to simply set a Boolean flag (whether an instance variable of an object or a global variable) to denote that an event has occurred and to suppress posting of further notifications until the flag is cleared. If this is not possible, however, in this situation you cannot directly use NSNotificationCenter since its behavior is synchronous—notifications are posted before returning, thus there is no opportunity for "ignoring” duplicate notifications; moreover, an NSNotificationCenterinstance has no way of knowing whether more notifications are coming or not.
在某些情况下,它可能只是简单的去设置一个布尔标识(不管是一个对象的实例变量还是全局变量)用来表示一个事件已经发生了,在这个标识被清空前需要抑制更进一步的发布通知。如果不能这样做,那么在这种情况下你就会因为它的行为是同步的而不能直接使用NSNotificationCenter——通知在返回前被发布,这样就没有机会“忽略”重复的通知,而且,统治中心实例也没有办法知道是否有更多的通知到来。
Rather than posting a notification to a notification center, therefore, you can add the notification to an NSNotificationQueueinstance specifying an appropriate option for coalescing. Coalescing is a process that removes from a queue notifications that are similar in some way to a notification that was queued earlier. You indicate the criteria for similarity by specifying one or more of the following constants in the third argument of the enqueueNotification:postingStyle:coalesceMask:forModes: method.
与其发布一个通知到统治中心,倒不如添加通知到一个NSNotificationQueue实例并制定合适的条件使其聚合。聚合是将较早在队列里面排队的并在某些方面相似的通知移除的过程,你可以通过指定一个或者多个限制条件作为以下方法的第三个参数,来标示相似的标准。
NSNotificationNoCoalescing
Do not coalesce notifications in the queue.
不在队列里面聚合通知
NSNotificationCoalescingOnName
Coalesce notifications with the same name.
以相同的名称聚合通知
NSNotificationCoalescingOnSender
Coalesce notifications with the same object.
以相同的对象聚合通知
You can perform a bitwise-OR operation with the NSNotificationCoalescingOnName and NSNotificationCoalescingOnSenderconstants to specify coalescing using both the notification name and notification object. The following example illustrates how you might use a queue to ensure that, within a given event loop cycle, all notifications named MyNotificationName are coalesced into a single notification. 
你可以使用按位或操作使用NSNotificationCoalescingOnNameNSNotificationCoalescingOnSender来指定同时按照名称和对象进行聚合。下面的例子说明了如何使用一个队列去验证这个规则,例子中已经给定了一个事件循环,所有名称为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];


Registering for a Notification
注册通知

You can register for notifications from within your own application or other applications. See “Registering for Local Notifications”for the former and “Registering for Distributed Notifications” for the latter. To unregister for a notification, which must be done when your object is deallocated, see “Unregistering an Observer.”

你可以从一个应用内注册一个通知,也可以从其他应用注册通知。可以先查看注册本地通知的相关内容,再查看注册分布式通知的相关内容。当注销一个通知时,当对象被销毁时通知必须完成。

Registering for Local Notifications

注册本地通知

You register an object to receive a notification by invoking the notification center method addObserver:selector:name:object:, specifying the observer, the message the notification center should send to the observer, the name of the notification it wants to receive, and about which object. You don’t need to specify both the name and the object. If you specify only an object, the observer will receive all notifications containing that object. If you specify only a notification name, the observer will receive that notification every time it’s posted, regardless of the object associated with it.

你可以调用通知中心的addObserver:selector:name:object:方法去注册一个对象接受通知消息,定制观察者,通知中心应该发送给观察者的消息,希望接收的通知名字,和接收哪一个对象的通知。你不需要详细说明通知名字和发送通知的对象,如果你只指定了发送通知的对象,观察者将会接收所有那个对象的通知。如果你只指定了通知名称,观察者将会接收这个通知每次发送的消息,而且不管这个通知是否与对象相关联。


It is possible for an observer to register to receive more than one message for the same notification. In such a case, the observer will receive all messages it is registered to receive for the notification, but the order in which it receives them cannot be determined. 
存在一种可能就是,一个观察者注册为接收同一个通知的不止一条消息。在这种情况下,这个观察者将会接收它注册的这个通知发送的所有消息,但是接收这些消息的顺序是无法确定的。


If you later decide an observer no longer needs to receive notifications (for example, if the observer is being deallocated), you can remove the observer from the notification center’s list of observers with the methods removeObserver: or removeObserver:name:object:.
如果你稍后希望观察者不再接收通知(例如,观察者对象被销毁),你可以使用removeObserver:或者removeObserver:name:object:方法从通知中心列表中移除这个观察者。


Normally, you register objects with the process’s default notification center. You obtain the default object using the defaultCenter class  method.
通常,你使用进程默认的通知中心注册观察者对象。你可以使用defaultCenter 类方法获得默认的通知中心对象。


As an example of using the notification center to receive notifications, suppose you want to perform an operation any time a window becomes main (for example, if you’re implementing a controller for an inspector panel). You would register your client object as an observer as shown in the following example:
下面是一个使用通知中心接收通知的例子,假设你想在某个时间执行一个操作将窗口变为主窗口,你可以按照如下代码所示的方式将一个客户端对象作为一个观察者对象注册到通知中心。

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

By passing nil as the object to observe, the client object (self) is notified when any object posts a NSWindowDidBecomeMainNotification notification.
传递一个nil 作为对象给观察者,那么任何对象发布的NSWindowDidBecomeMainNotification通知都会通知给这个观察者。


When window becomes main, it posts an NSWindowDidBecomeMainNotification to the notification center. The notification center notifies all observers who are interested in the notification by invoking the method they specified in the selector argument of addObserver:selector:name:object:. In the case of our example observer, the selector is aWindowBecameMain:. The aWindowBecameMain: method might have the following implementation:
当窗口变为主窗口,它发布一个NSWindowDidBecomeMainNotification通知到通知中心,通知中心通知所有对这个通知感兴趣的观察者,观察者是调用addObserver:selector:name:object:方法并指定相关参数来告诉通知中心自己对那些通知感兴趣的。在我们例子中的这种情况,接收到通知后,观察者响应的方法是aWindowBecameMain:,这个方法可能的实现方式如下所示:

- (void)aWindowBecameMain:(NSNotification *)notification {
 
    NSWindow *theWindow = [notification object];
    MyDocument = (MyDocument *)[[theWindow windowController] document];
 
    // Retrieve information about the document and update the panel.
}

The NSWindow objects don’t need to know anything about your inspector panel.

Registering for Distributed Notifications

An object registers itself to receive a notification by sending the addObserver:selector:name:object:suspensionBehavior:method to an NSDistributedNotificationCenter object, specifying the message the notification should send, the name of the notification it wants to receive, the identifying string to match (the object argument), and the behavior to follow if notification delivery is suspended.

Because the posting object and the observer may be in different processes, notifications can’t contain pointers to arbitrary objects. Therefore, the NSDistributedNotificationCenter class requires notifications to use an NSString object as the objectargument. Notification matching is done based on this string, rather than an object pointer. You should check the documentation of the object posting the notification to see what it uses as its identifying string.

When a process is no longer interested in receiving notifications immediately, it may suspend notification delivery. This is often done when the application is hidden, or is put into the background. (The NSApplication object automatically suspends delivery when the application is not active.) The suspensionBehavior argument in the addObserver method identifies how arriving notifications should be handled while delivery is suspended. There are four different types of suspension behavior, each useful in different circumstances.

Suspension Behavior

Description

NSNotificationSuspensionBehaviorDrop

The server does not queue any notifications with this name and object until it receives the setSuspended:NO message.

NSNotificationSuspensionBehaviorCoalesce

The server queues only the last notification of the specified name and object; earlier notifications are dropped. In cover methods for which suspension behavior is not an explicit argument, NSNotificationSuspensionBehaviorCoalesce is the default.

NSNotificationSuspensionBehaviorHold

The server holds all matching notifications until the queue has been filled (queue size determined by the server) at which point the server may flush queued notifications.

NSNotificationSuspensionBehaviorDeliverImmediately

The server delivers notifications matching this registration irrespective of whether it has received the setSuspended:YESmessage. When a notification with this suspension behavior is matched, it has the effect of first flushing any queued notifications. The effect is as if the server received setSuspended:NO while the application is suspended, followed by the notification in question being delivered, followed by a transition back to the previous suspended or unsuspended state.

You suspend notifications by sending setSuspended:YES to the distributed notification center. While notifications are suspended, the notification server handles notifications destined for the process that suspended notification delivery according to the suspension behavior specified by the observers when they registered to receive notifications. When the process resumes notification delivery, all queued notifications are delivered immediately. In applications using Application Kit, the NSApplicationobject automatically suspends notification delivery when the application is not active.

Note that a notification destined for an observer that registered with NSNotificationSuspensionBehaviorDeliverImmediately, automatically flushes the queue as it is delivered, causing all queued notifications to be delivered at that time as well.

The suspended state can be overridden by the poster of a notification. If the notification is urgent, such as a warning of a server being shut down, the poster can force the notification to be delivered immediately to all observers by posting the notification with the NSDistributedNotificationCenter postNotificationName:object:userInfo:deliverImmediately: method with the deliverImmediately argument YES.

Unregistering an Observer

Before an object that is observing notifications is deallocated, it must tell the notification center to stop sending it notifications. Otherwise, the next notification gets sent to a nonexistent object and the program crashes. You can send the following message to completely remove an object as an observer of local notifications, regardless of how many objects and notifications for which it registered itself:
在一个被注册到通知中心的对象被销毁前,它必须告诉通知中心停止向其发送通知。否则,下一个通知将会被发送给一个不存在的对象并导致程序崩溃。无论这个对象注册到了多少个通知中心,你都可以发送下面这条消息将它从本地通知中完全移除。
[[NSNotificationCenter defaultCenter] removeObserver:self];
For observers of distributed notifications send:
移除分布式通知的观察者发送:
[[NSDistributedNotificationCenter defaultCenter] removeObserver:self];
Use the more specific removeObserver... methods that specify the notification name and observed object to selectively unregister an object for particular notifications.
使用 removeObserver… 方法的更多特性去指定通知名称和从一个特定的通知中注销观察者对象。

Posting a Notification

You can post notifications within your own application or make them available to other applications. See “Posting Local Notifications” for the former and “Posting Distributed Notifications” for the latter.
你可以在你自己的应用内发布通知,也可以使你的通知在其他应用可见,前者阅读“Posting Local Notifications”,后者阅读“Posting Distributed Notifications” 。

Posting Local Notifications

You can create a notification object with notificationWithName:object: or notificationWithName:object:userInfo:. You then post the notification object to a notification center using the postNotification: instance method. NSNotification objects are immutable, so once created, they cannot be modified.
你可以使用notificationWithName:object: or notificationWithName:object:userInfo:方法创建通知。然后使用实例方法将通知对象发布到统治中心。通知对象是不可变的,所以一旦创建就不可以再修改。

However, you normally don’t create your own notifications directly. The methods postNotificationName:object: and postNotificationName:object:userInfo: of the NSNotificationCenter class allow you to conveniently post a notification without creating it first.
然而,你通常不会直接创建你自己的通知。通知中心的postNotificationName:object:postNotificationName:object:userInfo: 方法允许你方便的发送通知而不需要先创建它。

In each case, you usually post the notification to the process’s default notification center. You obtain the default object using the defaultCenter class method.
无论哪种情况,你通常将通知发布到进程默认的统治中心。你可以使用defaultCenter类方法获得这个通知中心对象。

As an example of using the notification center to post a notification, consider the example from “Registering for Local Notifications.” You have a program that can perform a number of conversions on text (for instance, RTF to ASCII). The conversions are handled by a class of objects (Converter) that can be added or removed during program execution. Your program may have other objects that want to be notified when converters are added or removed, but the Converter objects do not need to know who these objects are or what they do. You thus declare two notifications, "ConverterAdded" and "ConverterRemoved", which you post when the given event occurs.

When a user installs or removes a converter, it sends one of the following messages to the notification center:
当用户安装或者移除转换器时,它会发送下面的消息:
[[NSNotificationCenter defaultCenter]
    postNotificationName:@"ConverterAdded" object:self];

or

[[NSNotificationCenter defaultCenter]
    postNotificationName:@"ConverterRemoved" object:self];
The notification center then identifies which objects (if any) are interested in these notifications and notifies them.
通知中心会识别哪些对象对这些通知感兴趣并通知他们。
If there are other objects of interest to the observer (besides the notification name and observed object), place them in the notification’s optional dictionary or use postNotificationName:object:userInfo:.
这段是什么意思?userInfo到底干嘛用

Posting Distributed Notifications

Posting distributed notifications is much the same as for posting local notifications. You can create an NSNotification object manually and post with postNotification: or use one of the NSDistributedNotificationCenter convenience methods. The only differences are that the notification object must be a string object and the optional user-info dictionary can contain only property list objects, such as NSString and NSNumber.

An observer of a given notification may be in a suspended state and not processing notifications immediately. If an object posting a notification wants to ensure that all observers receive the notification immediately (for example, if the notification is a warning that a server is about to shut down), it can invoke postNotificationName:object:userInfo:deliverImmediately: with deliverImmediately:YES. The notification center delivers the notification as if the observers had registered with NSNotificationSuspensionBehaviorDeliverImmediately (further described in “Registering for Distributed Notifications”). Delivery is not guaranteed, however. For example, the process receiving the notifications may be too busy to process and accept queued notifications. In this case, the notification is dropped.

Delivering Notifications To Particular Threads

Regular notification centers deliver notifications on the thread in which the notification was posted. Distributed notification centers deliver notifications on the main thread. At times, you may require notifications to be delivered on a particular thread that is determined by you instead of the notification center. For example, if an object running in a background thread is listening for notifications from the user interface, such as a window closing, you would like to receive the notifications in the background thread instead of the main thread. In these cases, you must capture the notifications as they are delivered on the default thread and redirect them to the appropriate thread.

One way to redirect notifications is to use a custom notification queue (not an NSNotificationQueue object) to hold any notifications that are received on incorrect threads and then process them on the correct thread. This technique works as follows. You register for a notification normally. When a notification arrives, you test whether the current thread is the thread that should handle the notification. If it is the wrong thread, you store the notification in a queue and then send a signal to the correct thread, indicating that a notification needs processing. The other thread receives the signal, removes the notification from the queue, and processes the notification.

To implement this technique, your observer object needs to have instance variables for the following values: a mutable array to hold the notifications, a communication port for signaling the correct thread (a Mach port), a lock to prevent multithreading conflicts with the notification array, and a value that identifies the correct thread (an NSThread object). You also need methods to setup the variables, to process the notifications, and to receive the Mach messages. Here are the necessary definitions to add to the class of your observer object.

@interface MyThreadedClass: NSObject
/* Threaded notification support. */
@property NSMutableArray *notifications;
@property NSThread *notificationThread;
@property NSLock *notificationLock;
@property NSMachPort *notificationPort;
 
- (void) setUpThreadingSupport;
- (void) handleMachMessage:(void *)msg;
- (void) processNotification:(NSNotification *)notification;
@end

Before registering for any notifications, you need to initialize the properties. The following method initializes the queue and lock objects, keeps a reference to the current thread object, and creates a Mach communication port, which it adds to the current thread’s run loop.

- (void) setUpThreadingSupport {
    if (self.notifications) {
        return;
    }
    self.notifications      = [[NSMutableArray alloc] init];
    self.notificationLock   = [[NSLock alloc] init];
    self.notificationThread = [NSThread currentThread];
 
    self.notificationPort = [[NSMachPort alloc] init];
    [self.notificationPort setDelegate:self];
    [[NSRunLoop currentRunLoop] addPort:self.notificationPort
            forMode:(NSString __bridge *)kCFRunLoopCommonModes];
}

After this method runs, any messages sent to notificationPort are received in the run loop of the thread that first ran this method. If the receiving thread’s run loop is not running when the Mach message arrives, the kernel holds on to the message until the next time the run loop is entered. The receiving thread’s run loop sends the incoming messages to the handleMachMessage:method of the port’s delegate.

In this implementation, no information is contained in the messages sent to notificationPort. Instead, the information passed between threads is contained in the notification array. When a Mach message arrives, the handleMachMessage: method ignores the contents of the message and just checks the  notifications array for any notifications that need processing. The notifications are removed from the array and forwarded to the real notification processing method. Because port messages may get dropped if too many are sent simultaneously, the handleMachMessage: method iterates over the array until it is empty. The method must acquire a lock when accessing the notification array to prevent conflicts between one thread adding notifications and another removing notifications from the array.

- (void) handleMachMessage:(void *)msg {
 
    [self.notificationLock lock];
 
    while ([self.notifications count]) {
        NSNotification *notification = [self.notifications objectAtIndex:0];
        [self.notifications removeObjectAtIndex:0];
        [self.notificationLock unlock];
        [self processNotification:notification];
        [self.notificationLock lock];
    };
 
    [self.notificationLock unlock];
}

When a notification is delivered to your object, the method that receives the notification must identify whether it is running in the correct thread or not. If it is the correct thread, the notification is processed normally. If it is the wrong thread, the notification is added to the queue and the notification port signaled.

- (void)processNotification:(NSNotification *)notification {
 
    if ([NSThread currentThread] != notificationThread) {
        // Forward the notification to the correct thread.
        [self.notificationLock lock];
        [self.notifications addObject:notification];
        [self.notificationLock unlock];
        [self.notificationPort sendBeforeDate:[NSDate date]
                components:nil
                from:nil
                reserved:0];
    }
    else {
        // Process the notification here;
    }
}

Finally, to register for a notification that you want delivered on the current thread, regardless of the thread in which it may be posted, you must initialize your object’s notification properties by invoking setUpThreadingSupport and then register for the notification normally, specifying the special notification processing method as the selector.

[self setupThreadingSupport];
[[NSNotificationCenter defaultCenter]
        addObserver:self
        selector:@selector(processNotification:)
        name:@"NotificationName"
        object:nil];

This implementation is limited in several aspects. First, all threaded notifications processed by this object must pass through the same method (processNotification:). Second, each object must provide its own implementation and communication port. A better, but more complex, implementation would generalize the behavior into either a subclass of NSNotificationCenter or a separate class that would have one notification queue for each thread and be able to deliver notifications to multiple observer objects and methods.

Document Revision History

This table describes the changes to Notification Programming Topics.

Date Notes
2009-08-18 Added links to key Cocoa definitions.
2009-05-24 Removed obsolete references to Java classes.
2007-05-03 Noted that distributed notification centers deliver notifications on the main thread.
2007-01-08 Corrected minor typographical errors.
2006-11-07 Enhanced description of coalescing notifications.
2006-04-04 Clarified on which thread an enqueued notification is posted. Changed title from "Notifications."
 

Specified that notifications are posted on the same thread where they are enqueued in “Posting Notifications Asynchronously.”

 

Indicated that notifications are used throughout the Cocoa frameworks and pointed out where such notifications are described in “Notifications.”

2002-11-12

Revision history was added to existing topic. It will be used to record changes to the content of the topic.

Notification Centers 通知中心

标签:移动互联网   ios开发   通知中心   objective-c   

原文地址:http://blog.csdn.net/debolee/article/details/46335899

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!