iOS通知拾遗

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。通过组合任何NSNotificationNoCoalescingNSNotificationCoalescingOnNameNSNotificationCoalescingOnSender创建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

可见在子线程发送通知,在主线程处理通知

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值