iOS Notification(一):注册&发送

该文章的原创地址是:http://www.bignerdranch.com/blog/notifications-part-1-registering-and-posting/

介绍

Notification在Cocoa中是一个解藕的机制。假如你有一个对象,是一个网络监视器,此时你想告诉其他的对象,网络数据已经下载完毕。这个过程你可以使用很多方法来实现。

你可以下一个网络监听器的子类,并重载handleDisConnect方法。你也可以用target/action的方式去建立一个网络监听器,并关联自己的实现方法。你也可以用责任链的方式,或者用delegate的方式。还可以用这篇所介绍的方式:Notification。

许多实现方式都是1对1的方式,一种更好的方法是通过notification的方式在对象之间建立间接的关系,他们之间通过广播的方式进行通知。Notification center就像是在对象之间建立一个转发机构,当一个通知被发送到Notification center中,所有想要接受消息的对象就能接收到该消息。


右侧的三个对象(App Delegate,data viewer和logging system)都告诉Notification center他们对网络下载通知感兴趣。当网络下载完毕后,网络监听器告诉Notification center把这个消息通知给感兴趣的对象。通知方和接收方之间没有直接的关联,他们是通过广播的形式进行的。这种方式也被称作发现者模式

notification center像是一个中间人,对象可以通过它自由的像外界发送通知。这些发送通知的类不需要去继承特殊的类,也不需要实现特殊的接口。得益于OC的runtime机制,接收通知的类可以自定义任意selector去处理这些通知,而不需要实现任何接口和callback函数。

注册Notification

接收通知的类需要告诉notification center他们对某些感兴趣。notification center就会讲这些类和他们的处理函数纪录在一个内部的列表中,就像是一个电话本。当你开始编程前,这个列表基本上就是一个空的。


然后在一个对象中写上注册notification的表达式,告诉notification center它对某一个通知感兴趣。

[code]

// AppDelegate
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver: self
        selector: @selector(networkByeBye:)
        name: kNetworkWentByeByeNotification
        object: self.networkMonitor];

上面代码中,AppDelegate告诉notification center,当网络中断的时候,它想要接受到通知,也许它可能尝试重新连接。注意,代码中,AppDelegate对一个名叫kNetworkWentByeByeNotification的通知感兴趣,这是一个NSString类型的对象。如果networkMonitor发送一个名叫kNetworkWentByeByeNotification的通知,则AppDelegate就会用networkByeBye:去处理这个通知。Notification center会记录下AppDelegate,networkMonitor和selector的地址,并用kNetworkWentByeByeNotification来进行标注。


此时,对象DataViewer对象想要接收网络下载完毕的通知,然后可以改变用户界面,它也用相似的方式注册通知。

[code]

// DataViewer
[center addObserver: self
        selector: @selector(handleNetworkChange:)
        name: kNetworkWentByeByeNotification
        object: nil];

上面代码中Object传的参数是nil。这说明只要有任何对象发出kNetworkWentByeByeNotification的通知,它都能接收到,这点与AppDelegate不同,他只能接收来自networkMonitor的通知。

Notification center这个时候会在kNetworkWentByeByeNotification这个标签下增加一条记录,改记录中存储了DataViewer和selector的地址。


最后,logging system也想接受通知,这次使用使用一个较现代的API来注册通知,其中使用到了block和operation queue的技术。

[code]

// LogOTron
// _token is an instance variable of type 'id'
_token = [center addObserverForName: kNetworkWentByeByeNotification
                 object: nil
                 queue: [NSOperationQueue mainQueue]
                 usingBlock: ^(NSNotification *notification) {
                     NSLog (@"Network went down: %@", notification);
                 }];

上述代码是要告诉notification center,“当任何对象发送kNetworkWentByeByeNotification通知,就将block放到这个queue中去执行”,notification center会将这和对象的注册信息像前两次一样进行记录。


这个现代API与前两种最大的不同就是,没有对应的类和对象来处理这个notitification,前两种注册方式必须有一个对应的类或者对象来处理这个notification,而最后一种只需要提供一个block就就可以了,通过notification center中的记录信息也能看到最后一种方式的特殊之处。

发送Nofication

现在已经写好了注册通知的信息,但是什么效果都没有看到。notification center只是记录了有哪些对象对哪些通知感兴趣的信息,但是还没有对象来发送通知。

netword下载完成后,向notification center发送通知。

[code]

// NetworkMonitor
- (void) networkWentDown {
    // Collect the error
    // Pack the error and other information into a dictionary
    NSDictionary *userInfo = ...;

    // Post notification.
    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
    [center postNotificationName: kNetworkWentByeByeNotification
            object: self
            userInfo: userInfo];

} // networkWentDown

最后一行代码,告诉notification center发送一个名为kNetworkWentByeByeNotification的通知给感兴趣的对象。notification center接收到消息之后,通知kNetworkWentByeByeNotification标签下面的对象来接受通知,这个对象接收到通知之后,用之前注册好的selector或者queue来处理通知。

AppDelegate接收到消息之后,会用networkByeBye来处理通知。Logging system接受到通知后,将block放进main queue中执行。

注销通知

当一个对象对某一个通知不感兴趣之后,它应该从notification center中将注册信息注销掉。注销后,notification center就会删除关于改对象的记录信息,并断开和改selector的弱引用,但是如果使用的是block PAI的话,它还会保留对block的引用。所以这个时候要注意是否存在循环引用。当不再接收某个通知的时候,应该尽快的注销掉,或者在对象的dealloc时注销通知。

注销通知非常容易:

[code]

[center removeObserver: self];

上面的代码是将self中的所有注册的通知都注销掉,为了能比较安全的进行注销,因为指定注销特定的通知,因为有时候有些通知是深藏于Coca中的,此时如果注销掉可能会造成系统异常。

注销制定的通知

[code]

[center removeObserver: self
        name: kNetworkWentByeByeNotification
        object: nil];

上面的代码只是将kNetworkWentByeByeNotification通知注销掉的,但是其他的仍然保留。

Logging system中的通知注销要稍微麻烦一些,因为这个通知和改对象没有任何关联,用上面两种方式是无法注销的。所以需要在注册block型的通知时,要将注册信息保留下来,然后在你不需要的时候,在通过这个保留的信息将通知注销掉,上面代码中,是用了一个token的变量保留block API的,这个token是一个notificationcenter类型的变量。

这种block类型的API应该用下面这种方式进行注销:

[code]

[center removeObserver: _token];

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值