问题的背景
  • IOS中委托模式和消息机制基本上开发中用到的比较多,一般最开始页面传值通过委托实现的比较多,类之间的传值用到的比较多,不过委托相对来说只能是一对一,比如说页面A跳转到页面B,页面的B的值改变要映射到页面A,页面C的值改变也需要映射到页面A,那么就需要需要两个委托解决问题。NSNotificaiton则是一对多注册一个通知,之后回调很容易解决以上的问题。
概念

iOS消息通知机制算是同步的,观察者只要向消息中心注册, 即可接受其他对象发送来的消息,消息发送者和消息接受者两者可以互相一无所知,完全解耦。这种消息通知机制可以应用于任意时间和任何对象,观察者可以有多个,所以消息具有广播的性质,只是需要注意的是,观察者向消息中心注册以后,在不需要接受消息时需要向消息中心注销,属于典型的观察者模式。

消息通知中重要的两个类:
  • (1)NSNotificationCenter: 实现NSNotificationCenter的原理是一个观察者模式,获得NSNotificationCenter的方法只有一种,那就是[NSNotificationCenter defaultCenter] ,通过调用静态方法defaultCenter就可以获取这个通知中心的对象了。NSNotificationCenter是一个单例模式,而这个通知中心的对象会一直存在于一个应用的生命周期。

  • (2) NSNotification: 这是消息携带的载体,通过它,可以把消息内容传递给观察者。

使用
  • 1.通过NSNotificationCenter注册通知NSNotification,viewDidLoad中代码如下:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notificationFirst:) name:@"First" object:nil];

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notificationSecond:) name:@"Second" object:nil];

第一个参数是观察者为本身,第二个参数表示消息回调的方法,第三个消息通知的名字,第四个为nil表示表示接受所有发送者的消息~

回调方法:

-(void)notificationFirst:(NSNotification *)notification{
NSString *name=[notification name];
NSString *object=[notification object];
NSLog(@"名称:%@----对象:%@",name,object);
} -(void)notificationSecond:(NSNotification *)notification{
NSString *name=[notification name];
NSString *object=[notification object];
NSDictionary *dict=[notification userInfo];
NSLog(@"名称:%@----对象:%@",name,object);
NSLog(@"获取的值:%@",[dict objectForKey:@"key"]);
}
  • 2.消息传递给观察者
[[NSNotificationCenter defaultCenter] postNotificationName:@"First" object:@"博客园-Fly_Elephant"];

NSDictionary  *dict=[[NSDictionary alloc]initWithObjects:@[@"keso"] forKeys:@[@"key"]];

[[NSNotificationCenter defaultCenter] postNotificationName:@"Second" object:@"http://www.cnblogs.com/xiaofeixiang" userInfo:dict];
  • 3.销毁观察者
-(void)dealloc{
NSLog(@"观察者销毁了");
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
也可以通过name单个删除: [[NSNotificationCenter defaultCenter] removeObserver:self name:@"First" object:nil];
  • 4.运行结果
2015-04-26 15:08:25.900 CustoAlterView[2169:148380] 观察者销毁了
2015-04-26 15:08:29.222 CustoAlterView[2169:148380] 名称:First----对象:博客园-Fly_Elephant
2015-04-26 15:08:29.222 CustoAlterView[2169:148380] 名称:Second----对象:http://www.cnblogs.com/xiaofeixiang
2015-04-26 15:08:29.223 CustoAlterView[2169:148380] 获取的值:keso

深入分析观察者

  • 如果想让对象监听某个通知,则需要在通知中心中将这个对象注册为通知的观察者。早先,NSNotificationCenter提供了以下方法来添加观察者:
- (void)addObserver:(id)notificationObserver selector:(SEL)notificationSelector name:(NSString *)notificationName object:(id)notificationSender

这个方法带有4个参数,分别指定了通知的观察者、处理通知的回调、通知名及通知的发送对象。这里需要注意几个问题

notificationObserver不能为nil。

notificationSelector回调方法有且只有一个参数(NSNotification对象)。

如果notificationName为nil,则会接收所有的通知(如果notificationSender不为空,则接收所有来自于notificationSender的所有通知)。如代码清单1所示。

如果notificationSender为nil,则会接收所有notificationName定义的通知;否则,接收由notificationSender发送的通知。

监听同一条通知的多个观察者,在通知到达时,它们执行回调的顺序是不确定的,所以我们不能去假设操作的执行会按照添加观察者的顺序来执行。

对于以上几点,我们来重点关注一下第3条。以下代码演示了当我们的notificationName设置为nil时,通知的监听情况。

测试代码如下

添加一个Observer,其中notificationName为nil

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleNotification:) name:nil object:nil]; [[NSNotificationCenter defaultCenter] postNotificationName:TEST_NOTIFICATION object:nil];
} - (void)handleNotification:(NSNotification *)notification
{
NSLog(@"notification = %@", notification.name);
} @end
运行后的输出结果如下: notification = TestNotification
notification = UIWindowDidBecomeVisibleNotification
notification = UIWindowDidBecomeKeyNotification
notification = UIApplicationDidFinishLaunchingNotification
notification = _UIWindowContentWillRotateNotification
notification = _UIApplicationWillAddDeactivationReasonNotification
notification = _UIApplicationDidRemoveDeactivationReasonNotification
notification = UIDeviceOrientationDidChangeNotification
notification = _UIApplicationDidRemoveDeactivationReasonNotification
notification = UIApplicationDidBecomeActiveNotification

可以看出,我们的对象基本上监听了测试程序启动后的所示消息。当然,我们很少会去这么做。

而对于第4条,使用得比较多的场景是监听UITextField的修改事件,通常我们在一个ViewController中,只希望去监听当前视图中的UITextField修改事件,而不希望监听所有UITextField的修改事件,这时我们就可以将当前页面的UITextField对象指定为notificationSender。

NSNotification Block

在iOS 4.0之后,NSNotificationCenter为了跟上时代,又提供了一个以block方式实现的添加观察者的方法,如下所示:

  • (id)addObserverForName:(NSString *)name object:(id)obj queue:(NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *note))block

    大家第一次看到这个方法时是否会有这样的疑问:观察者呢?参数中并没有指定具体的观察者,那谁是观察者呢?实际上,与前一个方法不同的是,前者使用一个现存的对象作为观察者,而这个方法会创建一个匿名的对象作为观察者(即方法返回的id对象),这个匿名对象会在指定的队列(queue)上去执行我们的block。

这个方法的优点在于添加观察者的操作与回调处理操作的代码更加紧凑,不需要拼命滚动鼠标就能直接找到处理代码,简单直观。这个方法也有几个地方需要注意:

name和obj为nil时的情形与前面一个方法是相同的。

如果queue为nil,则消息是默认在post线程中同步处理,即通知的post与转发是在同一线程中;但如果我们指定了操作队列,情况就变得有点意思了,我们一会再讲。

block块会被通知中心拷贝一份(执行copy操作),以在堆中维护一个block对象,直到观察者被从通知中心中移除。所以,应该特别注意在block中使用外部对象,避免出现对象的循环引用,这个我们在下面将举例说明。

如果一个给定的通知触发了多个观察者的block操作,则这些操作会在各自的Operation Queue中被并发执行。所以我们不能去假设操作的执行会按照添加观察者的顺序来执行。

该方法会返回一个表示观察者的对象,记得在不用时释放这个对象。

下面我们重点说明一下第2点和第3点。

ios--->ios消息机制(NSNotification 和 NSNotificationCenter)的更多相关文章

  1. iOS开发-消息通知机制(NSNotification和NSNotificationCenter)

    iOS中委托模式和消息机制基本上开发中用到的比较多,一般最开始页面传值通过委托实现的比较多,类之间的传值用到的比较多,不过委托相对来说只能是一对一,比如说页面A跳转到页面B,页面的B的值改变要映射到页 ...

  2. 消息通知机制(NSNotification和NSNotificationCenter)

    作者:FlyElephant 出处:http://www.cnblogs.com/xiaofeixiang iOS中委托模式和消息机制基本上开发中用到的比较多,一般最开始页面传值通过委托实现的比较多, ...

  3. ios消息机制

    ios消息机制介绍 ios 调用每一个方法的时候其实是走的ios的消息机制 举例介绍一下 创建一个Pserson类 有一个eat 对象方法 那么下面的代码可以用消息机制实现  导入消息头文件    # ...

  4. IOS 消息机制(NSNotificationCenter)

    消息机制 NSNotificationCenter 一直都在频繁使用,但是却对其原理不是十分了解.今天就花些时间,把消息机制原理重头到尾好好过一遍. iOS 提供了一种 "同步的" ...

  5. iOS NSNotificationCenter(消息机制)

    转自:http://blog.csdn.net/liliangchw/article/details/8276803 对象之间进行通信最基本的方式就是消息传递,在Cocoa中提供Notificatio ...

  6. iOS开发系列--通知与消息机制

    概述 在多数移动应用中任何时候都只能有一个应用程序处于活跃状态,如果其他应用此刻发生了一些用户感兴趣的那么通过通知机制就可以告诉用户此时发生的事情.iOS中通知机制又叫消息机制,其包括两类:一类是本地 ...

  7. iOS开发系列--通知与消息机制--转

    来自:http://www.cocoachina.com/ios/20150318/11364.html 概述 在多数移动应用中任何时候都只能有一个应用程序处于活跃状态,如果其他应用此刻发生了一些用户 ...

  8. IOS开发-通知与消息机制

    在多数移动应用中不论什么时候都仅仅能有一个应用程序处于活跃状态.假设其它应用此刻发生了一些用户感兴趣的那么通过通知机制就能够告诉用户此时发生的事情. iOS中通知机制又叫消息机制,其包含两类:一类是本 ...

  9. iOS的消息转发机制详解

    iOS开发过程中,有一类的错误会经常遇到,就是找不到所调用的方法,当然这类问题比较好解决,给当前对象或其父类对象添加该方法即可,使得编译器在编译时能正确找到该方法:或者,还有另外的方法,由于Objec ...

随机推荐

  1. Cortex-A9 Timing

    在Cortex-A9的文档<Cortex-A9 NEON Media Processing Engine>Technical Reference Manual中有关于Instruction ...

  2. 修改jupyter notebook响应的浏览器

    Windows下更改jupyter notebook默认响应的浏览器为Chrome 1.命令行下输入:jupyter notebook --generate-config 2.C盘中找到并打开文件:C ...

  3. 虚拟机中linux系统无法打开原保存的显示器配置解决方法

    刚刚学习Linux,于是在虚拟机上装了一个redhat,有一次关机的时候,很长一段时间都没有关闭,似乎是死机了,于是我就用任务管理器给强制关闭了.然后再次开启系统就出现了这个问题,如下图所示: 当时我 ...

  4. 亲测可用的优雅的在已经安装了python的Ubuntu上安装python3.5

    我的Ubuntu上已经安装了python2.7和3.4. 用以下方法可以方便的顺利的安装python3.5,使用的时候也不会发生冲突. 一条一条输入以下语句 wget https://www.pyth ...

  5. 006 管理Ceph的RBD块设备

    一, Ceph RBD的特性 支持完整和增量的快照 自动精简配置 写时复制克隆 动态调整大小 二.RBD基本应用 2.1 创建RBD池 [root@ceph2 ceph]# ceph osd pool ...

  6. $HDOJ5542\ The\ Battle\ of\ Chibi$ 数据结构优化$DP$

    $AcWing$ $Description$ $Sol$ 首先显然是是以严格递增子序列的长度为阶段,由于要单调递增,所以还要记录最后一位的数值 $F[i][j]$表示前$i$个数中以$A_i$结尾的长 ...

  7. drop-out栈

    1.drop-out栈能够用来做什么? 在许多提供编辑功能的软件,如word.ps.画图,都会提供“撤销”和“恢复”功能,使用drop-out能够实现这些功能. 2.drop-out栈特性 drop- ...

  8. Markdown破解及汉化

    首先,附上用到的资源链接: 链接:https://pan.baidu.com/s/1ULvvCPcCv_P3KyD9ajXUjQ 提取码:5fkb 第一步 直接解压就可以,解压后运行该程序,会出现下图 ...

  9. Linux学习之路--常用配置

    1.修改IP地址 $vi /etc/sysconfig/network-scripts/ifcfg-eth0 BOOTPROTO=staticONBOOT=yesIPADDR=192.168.2.12 ...

  10. 10_时间戳timeStamp 和 时间 time 转换, 根据时间节点倒计时

    1: 时间戳 timeStamp 获取的几种方法及其优劣, 第一种只能精确到秒, 故不推荐使用, 最最常用的也是最官方的是第三种, 通过原型方法进行调用获取精确到毫秒数 : var timestamp ...