接收与发送Notification

接收Notification

一个通知分成几个部分

  1. object :发送者,是谁送出了这个通知
  2. name :这个通知叫做什么名字
  3. user info :这个通知还带了哪些额外资讯

所以,当我们想要监听某个通知的时候,便是指定要收听由谁所发出、哪个名字的通知,并且指定负责处理通知的selector,以前面处理locale 改变的例子来看,我们就会写出这样的code:

- (void)viewDidLoad
{
    [super viewDidLoad];
    [[NSNotificationCenter defaultCenter] addObserver:self
      selector:@selector(localeDidChange:)
      name:NSCurrentLocaleDidChangeNotification
      object:nil];
}

- (void)localeDidChange:(NSNotification *)notification
{
   // 處理 locale 改變的狀況
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

意思就是,我们要指定name为NSCurrentLocaleDidChangeNotification的通知,交由localeDidChange:处理。在这边object设定为nil,代表不管是哪个实例送出的,只要符合NSCurrentLocaleDidChangeNotification的通知,我们统统都处理。

每个通知当中,还可能会有额外的资讯,会夹带在NSNotification 物件的userInfo 属性中,userInfo 是一个NSDictionary。

像是我们如果让某个text field 变成了first responder,那么,在iOS 上,就会出现键盘,而当键盘出现的时候,我们往往要调整画面的layout,而键盘在不同输入法下的大小不一样,像是跟英文键盘比较起来,中文输入键盘上面往往会有一块组字区,而造成中文键盘比英文键盘大。在键盘升起来的时候,我们会收到UIKeyboardWillShowNotification 这项通知,而这项通知就会用userInfo 告诉我们键盘尺寸与位置。

如果我们在-addObserver:selector:name:object:里头,把name指定成nil,就代表我们想要订阅所有的通知,通常不太会有这种情境,不过有时候你想要知道系统内部发生了什么事情,可以用这种方式试试看。

当我们不需要继续订阅某项通知的时候,记得对Notification Center呼叫-removeObserver:,以上面的程式为例,我们在add observer的时候传入了self,在remove observer的时候,就要传入self。我们通常在dealloc的时候停止订阅。

在iOS 4与Mac OS X 10.6之后,我们可以使用-addObserverForName:object:queue:usingBlock:这组使用block语法的API订阅通知,由于是传入block,所以我们就不必另外准备一个selector,可以将处理notification的程式与add observer的这段呼叫写在一起。而remove observer的写法也会不太一样:-addObserverForName:object:queue:usingBlock:会回传一个observer物件,我们想要停止订阅通知的时候,是对-removeObserver:传入之前拿到的observer物件。范例如下。

Add observer 的时候:

self.observer = [[NSNotificationCenter defaultCenter]
    addObserverForName:NSCurrentLocaleDidChangeNotification
    object:nil
    queue:[NSOperationQueue mainQueue]
    usingBlock:^(NSNotification *note) {
    // 處理 locale 改變的狀況
}];

Remove observer 的时候:

[[NSNotificationCenter defaultCenter] removeObserver:self.observer];

发送Notification

至于要发送notification,则是在建立了notification实例之后,对NSNotificationCenter调用-postNotification:即可。

这三组method 都可以用来发送notification。

- (void)postNotification:(NSNotification *)notification;
- (void)postNotificationName:(NSString *)aName
                      object:(id)anObject;
- (void)postNotificationName:(NSString *)aName
                      object:(id)anObject
                    userInfo:(NSDictionary *)aUserInfo;

Notification 与Threading

当我们订阅某个notification 之后,我们并不能够保证负责处理notification 的selector 或block 会在哪个thread 执行:这个notification 是在哪条thread 送出的,负责接受的selector 或是block,就会在哪条thread执行。

在惯例上,绝大多数的notification都会在main thread送出,之所以说「绝大多数」,就是因为有例外:像是在iOS上,如果我们接上耳机、拔除耳机,或是将音乐透过AirPlay送到Apple TV的时候,系统会透过AVAudioSessionRouteChangeNotification告诉我们音讯输出设备改变了1,这个通知就会发生在背景,而不是main thread。

不过,当我们在撰写自己的程式,要发送notification的时候,为了考虑其他开发者会预期在main thread收到notification,所以我们也就在main thread发送notification,像是透过GCD,把postNotification的呼叫送到dispatch_get_main_queue()上。

1 .参见苹果官方文件Responding to Route Changes - https://developer.apple.com/library/ios/documentation/Audio/Conceptual/AudioSessionProgrammingGuide/HandlingAudioHardwareRouteChanges/HandlingAudioHardwareRouteChanges.html

results matching ""

    No results matching ""