iOS通知拾遗
如下的例子,发送一个通知,在控制台输出一些信息
- (void)sendNofition{
NSLog(@"1.发送通知:%@", [NSThread currentThread]);
[[NSNotificationCenter defaultCenter] postNotificationName:@"EOCClass" object:nil userInfo:nil];
NSLog(@"3.发送通知结束");
}
- (void)handleNotification:(NSNotification*)notification{
NSLog(@"2.处理通知:%@", [NSThread currentThread]);
}
控制台输出顺序如下:
1.发送通知:<NSThread: 0x60000006a240>{number = 1, name = main}
2.处理通知:<NSThread: 0x60000006a240>{number = 1, name = main}
3.发送通知结束
上面的输出顺序表示其是一个同步的通知
异步通知
如下的异步通知:
- (void)notificationQueue{
NSNotification *notifi = [NSNotification notificationWithName:@"EOCClass" object:nil];
NSNotificationQueue *notificationQueue = [NSNotificationQueue defaultQueue];
NSLog(@"1.发送通知:%@", [NSThread currentThread]);
[notificationQueue enqueueNotification:notifi postingStyle:NSPostWhenIdle coalesceMask:NSNotificationNoCoalescing forModes:nil];
NSLog(@"3.发送通知结束");
}
控制台输出顺序为:
1.发送通知:<NSThread: 0x60800007fcc0>{number = 1, name = main}
3.发送通知结束
2.处理通知:<NSThread: 0x60800007fcc0>{number = 1, name = main}
方法
- (void)enqueueNotification:(NSNotification *)notification postingStyle:(NSPostingStyle)postingStyle coalesceMask:(NSNotificationCoalescing)coalesceMask forModes:(nullable NSArray<NSRunLoopMode> *)modes;
方法说明:使用指定的posting样式,聚合条件和runloop模式,将notification添加到notification队列中
-
notification
-指待添加的通知 -
postingStyle
-表示notification在什么时候被post到notification center中。可能的值为枚举NSPostingStyle
,包括:NSPostWhenIdle
空闲时发送NSPostASAP
尽快发送NSPostNow
马上发送
-
coalesceMask
-将通知属性与队列中通知的属性进行匹配时指示使用什么标准的mask。通过组合任何NSNotificationNoCoalescing
,NSNotificationCoalescingOnName
和NSNotificationCoalescingOnSender
创建mask -
modes
-只有runloop是modes
数组中提供的模式时,通知队列才将通知post到通知中心
通知与线程
如果在一个新的线程中来调用发送通知的方法,会有什么样的效果呢?
1.发送同步通知
[NSThread detachNewThreadSelector:@selector(sendNofition) toTarget:self withObject:nil];
detachNewThreadSelector:toTarget:withObject:
方法参考iOS多线程之NSThread
控制台输出为:
1.发送通知:<NSThread: 0x600000267200>{number = 3, name = (null)}
2.处理通知:<NSThread: 0x600000267200>{number = 3, name = (null)}
3.发送通知结束
可见通知在子线程中被发送,也在子线程中被处理
2.发送异步通知
[NSThread detachNewThreadSelector:@selector(notificationQueue) toTarget:self withObject:nil];
此时控制台输出结果为:
1.发送通知:<NSThread: 0x608000265440>{number = 3, name = (null)}
3.发送通知结束
可见异步通知在子线程中发出,但是并没有被处理
如果此时把NSPostWhenIdle
修改为NSPostNow
,表示马上post,再次调用
[NSThread detachNewThreadSelector:@selector(notificationQueue) toTarget:self withObject:nil];
......
- (void)notificationQueue{
NSNotification *notifi = [NSNotification notificationWithName:@"EOCClass" object:nil];
NSNotificationQueue *notificationQueue = [NSNotificationQueue defaultQueue];
NSLog(@"1.发送通知:%@", [NSThread currentThread]);
[notificationQueue enqueueNotification:notifi postingStyle:NSPostWhenIdle coalesceMask:NSNotificationNoCoalescing forModes:nil];
NSLog(@"3.发送通知结束");
}
此时输出结果为:
1.发送通知:<NSThread: 0x60800007e840>{number = 6, name = (null)}
2.处理通知:<NSThread: 0x60800007e840>{number = 6, name = (null)}
3.发送通知结束
此时通知在子线程中被发送,而且在子线程中被处理,可以理解NSPostNow
为同步
线程与通知的关系:每一个线程都有一个通知队列,线程结束之后,则通知队列也被释放
现在使线程不结束,是什么状况呢?
[NSThread detachNewThreadSelector:@selector(notificationQueue) toTarget:self withObject:nil];
- (void)notificationQueue{
NSNotification *notifi = [NSNotification notificationWithName:@"EOCClass" object:nil];
NSNotificationQueue *notificationQueue = [NSNotificationQueue defaultQueue];
NSLog(@"1.发送通知:%@", [NSThread currentThread]);
[notificationQueue enqueueNotification:notifi postingStyle:NSPostWhenIdle coalesceMask:NSNotificationNoCoalescing forModes:nil];
NSLog(@"3.发送通知结束");
//使线程不结束
NSPort *port = [NSPort new];
[[NSRunLoop currentRunLoop] addPort:port forMode:NSRunLoopCommonModes];
[[NSRunLoop currentRunLoop] run];
}
此时控制条输出为:
1.发送通知:<NSThread: 0x60000007bd00>{number = 3, name = (null)}
3.发送通知结束
2.处理通知:<NSThread: 0x60000007bd00>{number = 3, name = (null)}
可以看出,通知在子线程中被发送,也在子线程中被处理
通知合并
如果再创建一个通知,即现在有2个通知
- (void)notificationQueue{
NSNotification *notifiOne = [NSNotification notificationWithName:@"EOCClass" object:nil];
NSNotification *notifiTwo = [NSNotification notificationWithName:@"EOCClass" object:nil];
NSNotificationQueue *notificationQueue = [NSNotificationQueue defaultQueue];
NSLog(@"1.发送通知:%@", [NSThread currentThread]);
[notificationQueue enqueueNotification:notifiOne postingStyle:NSPostWhenIdle coalesceMask:NSNotificationNoCoalescing forModes:nil];
[notificationQueue enqueueNotification:notifiTwo postingStyle:NSPostWhenIdle coalesceMask:NSNotificationNoCoalescing forModes:nil];
NSLog(@"3.发送通知结束");
//使线程不结束
NSPort *port = [NSPort new];
[[NSRunLoop currentRunLoop] addPort:port forMode:NSRunLoopCommonModes];
[[NSRunLoop currentRunLoop] run];
}
控制台输出为:
1.发送通知:<NSThread: 0x608000074940>{number = 3, name = (null)}
3.发送通知结束
2.处理通知:<NSThread: 0x608000074940>{number = 3, name = (null)}
2.处理通知:<NSThread: 0x608000074940>{number = 3, name = (null)}
如果将NSNotificationNoCoalescing
修改为NSNotificationCoalescingOnName
,表示按名字合并
[notificationQueue enqueueNotification:notifiOne postingStyle:NSPostWhenIdle coalesceMask:NSNotificationCoalescingOnName forModes:nil];
[notificationQueue enqueueNotification:notifiTwo postingStyle:NSPostWhenIdle coalesceMask:NSNotificationCoalescingOnName forModes:nil];
此时,控制台输出为:
1.发送通知:<NSThread: 0x608000070180>{number = 3, name = (null)}
3.发送通知结束
2.处理通知:<NSThread: 0x608000070180>{number = 3, name = (null)}
可见处理通知只有一个,已合并
但此时如果将NSPostWhenIdle
修改为NSPostNow
,表示一个同步通知
[notificationQueue enqueueNotification:notifiOne postingStyle:NSPostNow coalesceMask:NSNotificationCoalescingOnName forModes:nil];
[notificationQueue enqueueNotification:notifiTwo postingStyle:NSPostNow coalesceMask:NSNotificationCoalescingOnName forModes:nil];
此时控制台输出为:
1.发送通知:<NSThread: 0x600000077580>{number = 3, name = (null)}
2.处理通知:<NSThread: 0x600000077580>{number = 3, name = (null)}
2.处理通知:<NSThread: 0x600000077580>{number = 3, name = (null)}
3.发送通知结束
此时通知并没有被合并,处理了2次
但其实上面的通知并不是一个真正的异步通知,我们希望的是,在一个线程中发送通知,而在另一个线程中处理通知
这里使用NSPort
,把port添加到哪个线程中,就在哪个线程中进行处理
_port = [[NSPort alloc] init];
_port.delegate = self;
[[NSRunLoop currentRunLoop] addPort:_port forMode:NSRunLoopCommonModes];
// 发送消息
- (void)SendPort{
NSLog(@"发送线程1: Thread:%@", [NSThread currentThread]);
[_port sendBeforeDate:[NSDate date] msgid:1212 components:nil from:nil reserved:0];
NSLog(@"发送结束3");
}
//处理消息
- (void)handlePortMessage:(NSPortMessage *)message{
NSLog(@"处理任务线程2:%@", [NSThread currentThread]);
NSObject *messageObj = (NSObject*)message;
NSLog(@"%@", [messageObj valueForKey:@"msgid"]);
}
发送通知
[NSThread detachNewThreadSelector:@selector(SendPort) toTarget:self withObject:nil];
此时控制台输出为:
发送线程1: Thread:<NSThread: 0x600000260c40>{number = 3, name = (null)}
发送结束3
处理任务线程2:<NSThread: 0x60800007e0c0>{number = 1, name = main}
1212
可见在子线程发送通知,在主线程处理通知