iOS 通知机制 Notifications (三)

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

发布本地通知

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: 或者 notificationWithName:object:userInfo:  创建一个通知。然后你用postNotification:实例方法发布通知到通知中心。NSNotification 是不可变对象,所以一旦创建,不可更改。


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.

当然,你通常不需要直接创建自己的通知。NSNotificationCenter 的 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.

使用通知中心发布通知的例子可以从 “Registering for Local Notifications.”中找,]。你有个程序,执行一些文本的转换(比如,从RTF 到ASCII)。对象的类(转换器)处理转化,它可以再程序执行期间被添加获取删除。你程序中可能有对象想直到转换器何时被添加何时被去除,但是转换器对象不需要这些对象的信息。于是你定义两个通知  "ConverterAdded" 和 "ConverterRemoved" 当事件发生时发布通知。

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:.

如果有其他观察者感兴趣的对象,可以把他们放在通知可选的字典里,或者使用 postNotificationName:object:userInfo:

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.

一种重新发布通知的方法是使用自定义的通知队列(注意不是NSNotificationQueue对象)去保存在不正确线程上收到的通知,然后在正确的线程上处理他们。这个技术是这样的。你正常注册一个通知。当通知到达时,你测试一下当前的线程是否应该处理通知。如果是错误的线程,你保持通知到队列。然后发送一个信号到正确的线程,告诉它一个通知需要处理。另外一个线程收到信号,从队列中移除通知,然后处理通知。

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.

为了实现这个技术,你的观察者对象需要以下值的实例变量:一个保存通知的可变数组,一个通知正确线程的通信端口(a Mach port),一个防止通知数组内多线程处理冲突的锁,一个标示正确线程(一个NSThread 对象)的值。你也需要方法去设置变量,去处理通知,去接收 Mach消息。下面是要添加到你观察者对象中的必要的定义。

@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.

在注册通知之前,你需要初始化这些属性,下面的方法初始化了队列和锁对象,保持了一个对当前线程对象的引用,以及创建了一个Mach通信端口,它将被添加到当前线程的 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.

在这个方法运行之后,任何发送到notificationPort的消息将会在首先运行这个方法的线程的run loop中被收到。如果Mach 消息到达时,接收者线程的run loop没有运行,内核被保持这个消息直到下次 run loop进入。接收者线程的run loop 发送未到达的消息到 端口代理的 handleMachMessage:方法。

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.


在这个实现中,发送到notificationPort的消息 没有包含任何信息。 相反,通知数组包含线程间传递的信息。当Mach信息到达时,handleMachMessage:方法忽略了消息的内容,只是检查通知数组中需要处理的通知。通知从数组中移除,然后传到真正处理通知的方法中。因为如果同时发送太多端口信息,信息可能会丢失。 handleMachMessage:方法会遍历数组,直到它为空。当访问通知数组时必须获取一个锁,以防止一个线程添加通知而另一个线程把通知从数组移除。

- (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.

这个实现在某些方面。首先,对象处理的所有线程的通知必须通过相同的方法(processNotification:)传递。第二,每一个对象都必须提供自己的实现和通信端口。一个更好,但是也更复杂的实现是。。。。有空补上,这段话有点复杂



  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值