关于通知中心,我们应该都去发过通知以及去监听这个通知,我们下面就做一个简单的探析。
首先我们可以先通过打断点的方式去
po [NSNotificationCenter defaultCenter]
去查看它的信息,我们会发现有很多系统的通知在里面,在里面我们可以找到我们发布的通知。下面的object就是指定接收哪个对象发出的通知。
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(dealThings) name:@"ZXDealThings" object:nil];
我们如果实现了下面这两个方法实现点击屏幕去发送通知,这样的话是先去执行输出1的语句,然后发送通知,下面的dealThings方法先把方法处理完成之后才会再反回去执行输出3这条语句。也就是说是同步执行的。
通知中心默认是以同步的方式发送通知的,也就是说,当一个对象发送了一个通知,只有当该通知的所有接受者都接受到了通知中心分发的通知消息并且处理完成后,发送通知的对象才能继续执行接下来的方法
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
NSLog(@"1");
[[NSNotificationCenter defaultCenter]postNotificationName:@"ZXDealThings" object:nil];
NSLog(@"3");
}
-(void)dealThings
{
NSLog(@"处理消息---%@",[NSThread currentThread]);
}
我们如果想要实现不去管下面的处理方法是否完成就去执行NSLog(@"3")这条语句的话,我们可以这么做。
NSNotification * notification = [NSNotification notificationWithName:@"ZXDealThings" object:nil];
//获取当前线程下的通知队列,每个线程有一个默认的通知队列
NSNotificationQueue * notificationQueue = [NSNotificationQueue defaultQueue];
NSLog(@"1");
[notificationQueue enqueueNotification:notification postingStyle:NSPostWhenIdle coalesceMask:NSNotificationNoCoalescing
forModes:@[NSRunLoopCommonModes]];
NSLog(@"3");
这里的enqueueNotification第一个参数就是要发送的通知。
第二个参数就是发送通知的类型有三个类型
NSPostWhenIdle = 1,空闲时发送
NSPostASAP = 2, 尽快发送
NSPostNow = 3 立即发送
第三个参数就是合并的规则,如果是同步的,合并是没有效果的。
NSNotificationNoCoalescing = 0,不合并
NSNotificationCoalescingOnName = 1,按通知的名字合并,也就是说名字相同的通知会被合并,但是如果我们coalesceMask:设置的不一样即使名字一样也会发两次
NSNotificationCoalescingOnSender = 2 按通知的发送者合并
第四个参数就是运行循环运行的模式
当我们如果是在子线程当中执行上面的那段代码,并且postingStyle还是设置的NSPostWhenIdle,处理通知的方法啊并没有执行.可能就是因为子线程已经销毁了,因为它在等运行循环空闲的时刻。我们其实可以开启子线程的运行循环让子线程不销毁,要想开启子线程的运行循环并且不结束,我们就需要去添加一个资源。
在子线程中调用的方法中加上这么几句话就可以了,下面是添加一个基于端口的输入源
NSPort * port = [NSPort new];
[[NSRunLoop currentRunLoop]addPort:port forMode:NSRunLoopCommonModes];
[[NSRunLoop currentRunLoop]run];
如果我们将NSPostWhenIdle改成NSPostNow的话就可以进行收到通知的处理并且是同步的。
当我们连续调用了view的setNeedsDisplay方法的时候,系统会帮我们做一个合并操作,只会调用一次drawRect方法,这个也是异步执行的。并不会马上执行drawRect方法
[self.blueView setNeedsDisplay];
[self.blueView setNeedsDisplay];
[self.blueView setNeedsDisplay];
[self.blueView setNeedsDisplay];
[self.blueView setNeedsDisplay];
我们在底层当中的消息的触发其实是依赖与端口的,我们想要在一个线程中发消息,在另一个线程中进行处理的话,我们可以用端口来实现,代码如下
@interface ViewController ()<NSPortDelegate>
{
NSPort *_port;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_port = [NSPort new];
_port.delegate = self;
//把端口加在哪个线程里面就在哪个线程处理
[[NSRunLoop currentRunLoop]addPort:_port forMode:NSRunLoopCommonModes];
}
//发送消息
-(void)sendPort
{
NSLog(@"发送消息 %@",[NSThread currentThread]);
[_port sendBeforeDate:[NSDate date] msgid:1000 components:nil from:nil reserved:0];
NSLog(@"发送结束");
}
//处理消息
-(void)handlePortMessage:(NSPortMessage *)message
{
NSLog(@"处理任务:%@",[NSThread currentThread]);
NSObject * obj = (NSObject *)message;
NSLog(@"%@",[obj valueForKey:@"msgid"]);
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[NSThread detachNewThreadSelector:@selector(sendPort) toTarget:self withObject:nil];
}