IOS消息分发(广播)机制

来源:互联网 发布:黑暗之魂3淘宝被禁 编辑:程序博客网 时间:2024/06/05 11:57

在IOS中,提供了通知机制(Notification),可以在对象间传递和接受信息。传递和接受信息的对象间甚至不需要知道对方的存在。究其本质来说,其实是设计模式中的观察者模式的应用。

通知机制

设想这么一个场景:我开发了一款pdf阅读器,当手机上的另一个App打开pdf文件时,通过Open in,选择我的pdf阅读器打开。这时候我的pdf阅读器会被lanuch,同时在其App delegate中application:openURL方法会被调用,在这里我可以获得要打开的pdf文件的URL。然后,我想在App的ViewController中通过调用其他方法来渲染显示pdf文件。那么问题来了,默认的App delegate是和程序的ViewController层面没有联系的,即它不知道ViewController Object的存在,那么我怎么通知ViewController来渲染打开pdf文件并将文件的URL传递过去呢?

可能有人想到通过在App delegate中定义属性记录URL,再在ViewController中通过sharedApplication方式获取。但这种方式我们应该何时调用渲染函数来打开pdf文件呢?

一种更好的方式,就是使用IOS中的Notification机制。

Notification机制允许我们在同一个设备上的单个App中,或多个App间传递消息,甚至在不同设备间传递消息。

Notification由三部分组成:发送消息者、消息中心(负责接送及转发消息)、消息订阅者三个部分。他们的关系如下图所示:




如图所示,Notification机制的流程为:

1、消息发出者(sender)与消息接受者(observer)通过Notification Center建立关系,sender和observer之间互相不知道对方的存在。

2、observer向Notification center注册感兴趣的消息(同一个消息可以被多次注册,这样observer会多次得到相同的消息通知)。

3、sender向Notification center发送消息。

4、Notification center接收到来自sender消息,自动根据注册信息向感兴趣的Observer转发消息。

5、Observer获得来自Notification center的消息处理。

Notification 实例

消息机制能够在同一App的各对象间、不同App间传递消息,这里,就先结合在单个App中的各对象间传递消息为例,来说明如何在代码中使用消息的。


还是以pdf阅读器为例,在App delegate的Open URL方法中,我们获知App因为打开文件而被打开,同时可以获取文件URL地址。这里我们发出一个名称OpenPDF的消息,同时将文件的URL地址作为object参数传递出去。

[objc] view plaincopy
  1. -(BOOL) application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation  
  2. {  
  3.     NSNotificationCenter* notify = [NSNotificationCenter defaultCenter]; // 获取Notification center对象,默认每个APP均有一个单例defaultCenter  
  4.       
  5.     [notify postNotificationName:@"OpenPDF" object:url];  
  6.     return YES;  
  7. }  


上面的处理中,有这么几点:

1、首先获得NSNotificationCenter对象,这里我们通过类方法获取了一个defaultCenter对象。在IOS中,每个App中都会有一个系统默认的defaultCenter对象。

2、我们向Notification center发送消息,调用了postNotificationName:object:方法。其实在该方法中,我们同时创建了一个Notification对象,该方法会将该消息对象发送到notification center中。(其实我们也可以先创建一个Notification对象,再通过调用方法发送该对象,但是现在使用的方法更简洁)

在IOS中,消息也是一个对象的形式存在的,其有三个属性如下:

[objc] view plaincopy
  1. @interface NSNotification : NSObject <NSCopying, NSCoding>  
  2.   
  3. @property (readonlycopyNSString *name;        // 消息名称  
  4. @property (readonlyretainid object;           // 消息附加的对象信息  
  5. @property (readonlycopyNSDictionary *userInfo;// 消息附加的用户自定义扩展信息  

上面三个属性的具体内容都是由sender定义的,其中name可以让我们区别是什么消息,而object和userInfor则可以附带一些消息发出时的附加信息供消息接受者处理。(object属性通常会设置为消息发出者自身self,这样observer就可以通过订阅时指定name 和 object属性来确定感兴趣的消息,并指定其来自那个object)。

3、observer注册感兴趣的消息到notification center,并指明处理消息的selector或块。

这里,在ViewController的viewDidLoad中,我注册了感兴趣的通知,OpenPDF。并指明处理的selector为openPDFAction:

[objc] view plaincopy
  1. - (void)viewDidLoad {  
  2.     [super viewDidLoad];  
  3.     // Do any additional setup after loading the view, typically from a nib.  
  4.     NSNotificationCenter* notify = [NSNotificationCenter defaultCenter];  
  5.     [notify addObserver:self selector:@selector(openPDFAction:) name:@"OpenPDF" object:nil];   
  6. }  

在订阅消息函数中,我们并没有指定要订阅那个object,所以不管是那个sender的消息,只要名字等于OpenPDF,则Notification center就会通知我们,并调用我们的处理函数openPDFAction。

4、处理函数的定义一般如下,其参数仅有一个,就是被转发过来的Notification对象,同时,没有返回值(因为一个消息可能会被转发至多个Observer,对于返回值来说就没有必要了,否则,你应使用那个处理函数的返回值呢?)

[objc] view plaincopy
  1. -(void) openPDFAction:(NSNotification*) sender  
  2. {  
  3.     NSURL* URL = (NSURL*)[sender object];  
  4.     if (URL) {  
  5.         self.documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:URL];  
  6.         [self.documentInteractionController setDelegate:self];  
  7.         [self.documentInteractionController presentPreviewAnimated:YES];  
  8.     }  
  9.   
  10. }  

OK,这样我们就完成了一个消息的处理流程了:sender发出消息到Notification center,Observer 注册感兴趣的消息到Notification center,Notification center在有消息时,会自动将消息发送给感兴趣的Observer。在这个流程中,sender和Observer始终不知道对方的存在,他们是通过Notification center建立联系的。


Notification机制的一些细节

1、在单个App中,我们通过NSNotificationCenter对象接收分发消息。若要再多个App间传递消息,则需要NSDistributedNotificationCenter对象。

2、利用NSNotificationCenter对象分发notification是同步的,即直到所有的Observer均接收到消息并处理完成后,调用消息分发的函数才会返回。若想异步处理消息分发,可以借助Notification Queues(一个为NSNotificationCenter对像配备的消息缓存)。

3、消息分发一般来说是不会跨线程的。对于NSNotificationCenter,消息只会在发出消息的线程中传递。对于NSDistributedNotificationCenter,消息只会传递到另一个App的主线程上。

若要实现消息的跨线程分发,一种方法是可以实现自定义的消息缓冲(不是系统的NSNotificationQueue对象),让其在正确的线程上接受消息,然后再像目标线程转发消息。

4、跨App的消息通过系统的转发中心转发,它会消耗大量系统资源,同时不能够保证消息的实时性。若系统中又过多的消息需要传递,IOS系统其实会丢弃一些跨App消息。同时,通过NSDistributedNotificationCenter传递的消息,其object参数仅能是NSString对象,在用户的自定义字典参数中,仅能够存储property list类型。

0 0