项目中需要使用消息机制进行模块解耦,页面C的值改变也需要映射到页面A

回调处理

图片 1

-(void) callBack1(NSNotification*)notification
{
    notification.name://通知的名称
    notification.object;//发送通知时的object
    notification.userInfo//发送通知时的userInfo
}

图片 2

  网上经常说iOS的通知机制是使用了观察者模式,里面有两个角色,其一是poster(发送者),另一个是observer(接受信息的订阅者)。但我认为重要的角色是通知中心,它是整个通知机制的核心,有poster发送者发送的消息必定要到达通知中心,再由通知中心根据这个消息被哪些observer订阅者订阅过,就把消息往那些订阅者去分发。整体可以与现在的电子邮件结构作类比的。但要额外说明一下,iOS的通知虽然也叫Notification通知,但是与Android中的通知是不一样的,在Android中的通知是一种消息推送的形式,而在iOS中肯定也有消息推送,这就是推送机制那部分的内容。说会这个通知机制的其实就是原本在学习C#时的事件,只不过这里的事件是对于整个系统的全局事件,任何一方往系统的这个全局事件去注册绑定了方法,到事件被触发的时候就能够被执行。

这个方法没有声明观察者,但是当事件发生时,会在指定的线程里面执行闭包.

深入分析观察者

如果想让对象监听某个通知,则需要在通知中心中将这个对象注册为通知的观察者。早先,NSNotificationCenter提供了以下方法来添加观察者:

- addObserver:notificationObserver selector:notificationSelector name:(NSString *)notificationName object:notificationSender

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

  1. notificationObserver不能为nil。
  2. notificationSelector回调方法有且只有一个参数(NSNotification对象)。
  3. 如果notificationName为nil,则会接收所有的通知(如果notificationSender不为空,则接收所有来自于notificationSender的所有通知)。如代码清单1所示。
  4. 如果notificationSender为nil,则会接收所有notificationName定义的通知;否则,接收由notificationSender发送的通知。
  5. 监听同一条通知的多个观察者,在通知到达时,它们执行回调的顺序是不确定的,所以我们不能去假设操作的执行会按照添加观察者的顺序来执行。

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

测试代码如下

添加一个Observer,其中notificationName为nil

@implementation ViewController- viewDidLoad { [super viewDidLoad]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleNotification:) name:nil object:nil]; [[NSNotificationCenter defaultCenter] postNotificationName:TEST_NOTIFICATION object:nil];}- handleNotification:(NSNotification *)notification{ NSLog(@"notification = %@", notification.name);}@end

运行后的输出结果如下:

notification = TestNotificationnotification = UIWindowDidBecomeVisibleNotificationnotification = UIWindowDidBecomeKeyNotificationnotification = UIApplicationDidFinishLaunchingNotificationnotification = _UIWindowContentWillRotateNotificationnotification = _UIApplicationWillAddDeactivationReasonNotificationnotification = _UIApplicationDidRemoveDeactivationReasonNotificationnotification = UIDeviceOrientationDidChangeNotificationnotification = _UIApplicationDidRemoveDeactivationReasonNotificationnotification = UIApplicationDidBecomeActiveNotification

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

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

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

- (id<NSObject>)addObserverForName:(NSString *)name object:obj queue:(NSOperationQueue *)queue usingBlock:(NSNotification *note))block

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

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

  1. name和obj为nil时的情形与前面一个方法是相同的。
  2. 如果queue为nil,则消息是默认在post线程中同步处理,即通知的post与转发是在同一线程中;但如果我们指定了操作队列,情况就变得有点意思了,我们一会再讲。
  3. block块会被通知中心拷贝一份,以在堆中维护一个block对象,直到观察者被从通知中心中移除。所以,应该特别注意在block中使用外部对象,避免出现对象的循环引用,这个我们在下面将举例说明。
  4. 如果一个给定的通知触发了多个观察者的block操作,则这些操作会在各自的Operation
    Queue中被并发执行。所以我们不能去假设操作的执行会按照添加观察者的顺序来执行。
  5. 该方法会返回一个表示观察者的对象,记得在不用时释放这个对象。

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

关于第2点,当我们指定一个Operation
Queue时,不管通知是在哪个线程中post的,都会在Operation
Queue所属的线程中进行转发:

代码如下:在指定队列中接收通知

@implementation ViewController- viewDidLoad { [super viewDidLoad]; [[NSNotificationCenter defaultCenter] addObserverForName:TEST_NOTIFICATION object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { NSLog(@"receive thread = %@", [NSThread currentThread]); }]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSLog(@"post thread = %@", [NSThread currentThread]); [[NSNotificationCenter defaultCenter] postNotificationName:TEST_NOTIFICATION object:nil]; });}@end

在这里,我们在主线程里添加了一个观察者,并指定在主线程队列中去接收处理这个通知。然后我们在一个全局队列中post了一个通知。我们来看下输出结果:

post thread = <NSThread: 0x7ffe0351f5f0>{number = 2, name = }receive thread = <NSThread: 0x7ffe03508b30>{number = 1, name = main}

可以看到,消息的post与接收处理并不是在同一个线程中。如上面所提到的,如果queue为nil,则消息是默认在post线程中同步处理,大家可以试一下。

对于第3点,由于使用的是block,所以需要注意的就是避免引起循环引用的问题,如下:

block引发的循环引用问题

@interface Observer : NSObject@property (nonatomic, assign) NSInteger i;@property (nonatomic, weak) id<NSObject> observer;@end@implementation Observer- (instancetype)init{ self = [super init]; if  { NSLog(@"Init Observer"); // 添加观察者 _observer = [[NSNotificationCenter defaultCenter] addObserverForName:TEST_NOTIFICATION object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { NSLog(@"handle notification"); // 使用self self.i = 10; }]; } return self;}@end·#pragma mark - ViewController@implementation ViewController- viewDidLoad { [super viewDidLoad]; [self createObserver]; // 发送消息 [[NSNotificationCenter defaultCenter] postNotificationName:TEST_NOTIFICATION object:nil];}- createObserver { Observer *observer = [[Observer alloc] init];}@end

运行后的输出如下:

Init Observerhandle notification

我们可以看到createObserver中创建的observer并没有被释放。所以,使用 –
addObserverForName:object:queue:usingBlock:一定要注意这个问题。

iOS通知机制,ios通知

  网上经常说iOS的通知机制是使用了观察者模式,里面有两个角色,其一是poster(发送者),另一个是observer(接受信息的订阅者)。但我认为重要的角色是通知中心,它是整个通知机制的核心,有poster发送者发送的消息必定要到达通知中心,再由通知中心根据这个消息被哪些observer订阅者订阅过,就把消息往那些订阅者去分发。整体可以与现在的电子邮件结构作类比的。但要额外说明一下,iOS的通知虽然也叫Notification通知,但是与Android中的通知是不一样的,在Android中的通知是一种消息推送的形式,而在iOS中肯定也有消息推送,这就是推送机制那部分的内容。说会这个通知机制的其实就是原本在学习C#时的事件,只不过这里的事件是对于整个系统的全局事件,任何一方往系统的这个全局事件去注册绑定了方法,到事件被触发的时候就能够被执行。

         整个通知的操作流程,我们只需要把poster和observer设置好就可以了

对于Poster的操作比较简单,他只需要往通知中心推通知就可以了,采用以下的代码

[[NSNotificationCenter defaultCenter] postNotificationName:@”PostOne” object:@”This is posterone”];

或者

[[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:@”PostOne” object:@”This is posterone”]];

NotificationWithName: object: 方法还有一个重载就是有userInfo:
参数,它是NSDictionary的字典类型,就是用于传递用户参数。

  对于Observer则相对没Poster那么简单,在C#中进行事件注册绑定的时候也发现,触发事件的只需要像调用方法那样子调用就可以了,但是注册那一方则需要为事件绑定方法,又要定义方法,而在iOS的通知机制中,需要注册,回调处理(就是事件中的方法定义),用完了还要去删除。

对于Poster的操作比较简单,他只需要往通知中心推通知就可以了,采用以下的代码

name 和 object 意义同上.

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

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

消息通知中重要的两个类:

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

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表示表示接受所有发送者的消息~

回调方法:

-notificationFirst:(NSNotification *)notification{ NSString *name=[notification name]; NSString *object=[notification object]; NSLog(@"名称:%@----对象:%@",name,object);} -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.销毁观察者

-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_Elephant2015-04-26 15:08:29.222 CustoAlterView[2169:148380] 名称:Second----对象:http://www.cnblogs.com/xiaofeixiang2015-04-26 15:08:29.223 CustoAlterView[2169:148380] 获取的值:keso

删除

在使用消息完毕(就是不再对接收到的消息作处理的)之后,需要进行删除操作

[[NSNotificationCenter defaultCenter]removeObserver: self];//删除所有注册过的通知
[[NSNotificationCenter defaultCenter]removeObserver:self name:@”PostOne“ object:nil];//删除名称为”PostOne“的通知。

 

网上经常说iOS的通知机制是使用了观察者模式,里面有两个角色,其一是poster(发送者),另一个是observer(接受信息的…

         整个通知的操作流程,我们只需要把poster和observer设置好就可以了

任意位置注册/移除事件
,主要考虑在事件分发过程中,如果改变了遍历中的事件列表
,可能造成遍历结束条件异常(如增加了事件或者移除了事件),
一般来说有下面几种方式解决,

注册

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(callBack1:) name:@”PostOne” object: nil];

这里的参数是跟postNotificationName:
object:对应的。注册了哪个通知name参数就填上对对应的值

  对于Observer则相对没Poster那么简单,在C#中进行事件注册绑定的时候也发现,触发事件的只需要像调用方法那样子调用就可以了,但是注册那一方则需要为事件绑定方法,又要定义方法,而在iOS的通知机制中,需要注册,回调处理(就是事件中的方法定义),用完了还要去删除。

希望大家点个星 🙂

或者

加锁,遍历过程中,添加/移除/发送 消息 记录到缓冲区.待遍历结束执行.

回调处理

-(void) callBack1(NSNotification*)notification
{
    notification.name://通知的名称
    notification.object;//发送通知时的object
    notification.userInfo//发送通知时的userInfo
}

lua 本身不支持多线程,因此没有线程安全问题.

注册

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(callBack1:) name:@”PostOne” object: nil];

这里的参数是跟postNotificationName:
object:对应的。注册了哪个通知name参数就填上对对应的值

健壮:能感知错误输入,及时抛出错误

[[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:@”PostOne” object:@”This is posterone”]];

NotificationWithName: object: 方法还有一个重载就是有userInfo:
参数,它是NSDictionary的字典类型,就是用于传递用户参数。

addObserver:selector:name:object:

删除

在使用消息完毕(就是不再对接收到的消息作处理的)之后,需要进行删除操作

[[NSNotificationCenter defaultCenter]removeObserver: self];//删除所有注册过的通知
[[NSNotificationCenter defaultCenter]removeObserver:self name:@”PostOne“ object:nil];//删除名称为”PostOne“的通知。

 

安全:不能造成内存泄露,
能任意位置注册/移除事件,包括在事件回调过程中.在多线程编程环境下,还要保证线程安全.

[[NSNotificationCenter defaultCenter] postNotificationName:@”PostOne” object:@”This is posterone”];

通知中心作为程序的基础框架,它应该具备以下三个特点:

assert(event,”notificationCenter addObserve, event eq nil”)

assert(observer,”notificationCenter addObserve; observer eq nil”)

assert(func,”notificationCenter addObserve; func eq nil”)

发表评论

电子邮件地址不会被公开。 必填项已用*标注

相关文章