标签:移动互联网 ios开发 通知中心 objective-c
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.
NSDistributedNotificationCenter
class manages notifications across multiple processes on a single computer.NSNotification对象中。客户对象将自身注册到通知中心作为从其他对象发送来的具体通知的观察者。当一个事件发生时,对象将发布一个合适的通知到通知中心(查看
“Posting
a Notification”了解更多)。通知中心分派一个消息到每一个被注册的观察者,并作为唯一的参数传递通知。存在发送者对象和观察者对象是同一个对象的可能。NSNotificationCenter
类管理单进程内的通知。NSDistributedNotificationCenter
类在一台计算中通过多进程管理通知。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.”
NSNotificationCenter类的+defaultCenter类
方法进行访问。这个通知中心控制着这个进程内的通知。你可以使用分布式通知中心实现不同进程间的通信 (see “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.
发布一个分布式通知是一个开销很大的操作。通知被发送到系统服务,然后再被系统服务分发到所有注册了分布式通知的对象的进程。发布通知与通知到达另外一个进程之间的潜在因素是不受控的。实际上,如果发布了太多的通知导致服务队列被填满,通知会被删除。
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.NSDefaultRunLoopMode
,去接收分布式通知。如果接收进程是多线程的,不依赖于到达主线程的通知。通知通常被传送到主线程的运行循环,但是其他的线程也可以接收这个通知。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. NSNotificationQueue
类为Foundation
Kit的通知机制贡献了两个重要的功能:聚合通知和异步发布通知。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.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.NSNotificationQueue
的enqueueNotification:postingStyle:
和enqueueNotification:postingStyle:coalesceMask:forModes:方法,你可以将通知放进队列异步地发布到当前线程,这些方法把通知放入队列后立即返回到调用对象。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”
了解更多信息。NSPostASAP
, NSPostWhenIdle
,
and NSPostNow
. These styles are described in the following sections. NSPostASAP
, NSPostWhenIdle
,
和 NSPostNow
.这些格式在接下来的段落中进行描述。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可能被优先处理,例如时间或者资源占用,或者其他异步通知正在传送。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.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.
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.
NSNotificationCenter
since its behavior is synchronous—notifications are posted
before returning, thus there is no opportunity for "ignoring” duplicate notifications; moreover, an NSNotificationCenter
instance has no way of knowing whether more notifications
are coming or not.NSNotificationCenter——通知在返回前被发布,这样就没有机会“忽略”重复的通知,而且,统治中心实例也没有办法知道是否有更多的通知到来。
NSNotificationQueue
instance 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.
以相同的对象聚合通知
|
NSNotificationCoalescingOnName
and NSNotificationCoalescingOnSender
constants
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. 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];
|
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.”
你可以从一个应用内注册一个通知,也可以从其他应用注册通知。可以先查看注册本地通知的相关内容,再查看注册分布式通知的相关内容。当注销一个通知时,当对象被销毁时通知必须完成。
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:方法去注册一个对象接受通知消息,定制观察者,通知中心应该发送给观察者的消息,希望接收的通知名字,和接收哪一个对象的通知。你不需要详细说明通知名字和发送通知的对象,如果你只指定了发送通知的对象,观察者将会接收所有那个对象的通知。如果你只指定了通知名称,观察者将会接收这个通知每次发送的消息,而且不管这个通知是否与对象相关联。
removeObserver:
or removeObserver:name:object:
.defaultCenter
class method.defaultCenter
类方法获得默认的通知中心对象。
[[NSNotificationCenter defaultCenter] addObserver:self |
selector:@selector(aWindowBecameMain:) |
name:NSWindowDidBecomeMainNotification object:nil]; |
nil
as the object to observe, the client object (self
)
is notified when any object posts a NSWindowDidBecomeMainNotification
notification.nil
作为对象给观察者,那么任何对象发布的NSWindowDidBecomeMainNotification
通知都会通知给这个观察者。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.
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 |
---|---|
|
The server does not queue any notifications with this name and object until it receives the |
|
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, |
|
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. |
|
The server delivers notifications matching this registration irrespective of whether it has received the |
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 NSApplication
object 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
.
[[NSNotificationCenter defaultCenter] removeObserver:self]; |
[[NSDistributedNotificationCenter defaultCenter] removeObserver:self]; |
removeObserver...
methods that specify the notification name and observed object to selectively unregister an object
for particular notifications.removeObserver…
方法的更多特性去指定通知名称和从一个特定的通知中注销观察者对象。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:方法创建通知。然后使用实例方法将通知对象发布到统治中心。通知对象是不可变的,所以一旦创建就不可以再修改。
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:
方法允许你方便的发送通知而不需要先创建它。defaultCenter
class
method.defaultCenter
类方法获得这个通知中心对象。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.
[[NSNotificationCenter defaultCenter] |
postNotificationName:@"ConverterAdded" object:self]; |
or
[[NSNotificationCenter defaultCenter] |
postNotificationName:@"ConverterRemoved" object:self]; |
postNotificationName:object:userInfo:
.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
.
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.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.
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. |
标签:移动互联网 ios开发 通知中心 objective-c
原文地址:http://blog.csdn.net/debolee/article/details/46335899