一、通知的基本使用
每一个应用程序都有一个通知中心,专门负责协助不同 对象之间的消息通信。
任何一个对象都可以向通知中心发布通知,描述自己在做什么。其他感兴趣的对象可以申请在某个特定通知发布时(或在某个特定的对象发布通知时)收到这个通知。
//一个通知一般包含三个属性:
@property (readonly, copy) NSString *name;//通知名称
@property (nullable, readonly, retain) id object;//通知发布者(是谁要发布通知)
@property (nullable, readonly, copy) NSDictionary *userInfo;//一些额外的信息(通知发布者传递给通知接收者的信息内容)
//初始化一个通知:(NSNotification)对象
+ (instancetype)notificationWithName:(NSString *)aName object:(nullable id)anObject;
+ (instancetype)notificationWithName:(NSString *)aName object:(nullable id)anObject userInfo:(nullable NSDictionary *)aUserInfo;
//发布通知方法(通知中心提供了相应的方法来帮助发布通知)
//1.发布一个notification通知,可在notification对象中设置通知的名称,通知发布者、额外的信息等
- (void)postNotification:(NSNotification *)notification;
//2.发布一个名称为aName的通知,anObject为这个通知的发布者
- (void)postNotificationName:(NSString *)aName object:(nullable id)anObject;
//3.发布一个名称为aName的通知,anObject为这个通知的发布者,aUserInfo为额外信息(通知的内容)
- (void)postNotificationName:(NSString *)aName object:(nullable id)anObject userInfo:(nullable NSDictionary *)aUserInfo;
在这里举个例子,比如这里有新浪和腾讯新闻在发布新闻。张三喜欢收听娱乐新闻,李四喜欢收听搞笑新闻。当新浪和腾讯发出的新闻只要是娱乐新闻张三都能收听到,发出的新闻只要是搞笑新闻李四都能收听到,怎么实现呢,看如下代码:
//首先创建一个新闻发布类,有一个属性名字(比如新浪和腾讯)
#import <Foundation/Foundation.h>
@interface NewsCompany : NSObject
@property (nonatomic, copy) NSString *name;
@end
//再创建一个Person类(有一个name属性和接收到新闻后做出的回应)
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
//接收到消息后触发的方法
- (void)newCome:(NSNotification *)note;
@end
//Person.m文件中实现接收到通知后的方法
#import "Person.h"
#import "NewsCompany.h"
@implementation Person
- (void)newCome:(NSNotification *)note{
//取到通知发布者
NewsCompany *obj = note.object;
NSLog(@"%@接收到%@的通知,通知内容是:%@",self.name,obj.name, note.userInfo);
}
//通知中心不会保留(retain)监听器对象,在通知中心注册过的对象,必须在该对象释放前取消注册。否则,当相应的通知再次出现时,通知中心仍然会向该监听器发送消息。因为相应的监听器对象已经被释放了,所以可能会导致应用崩溃
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
//然后我们在ViewController.m文件中实现他们
//首先创建两个新闻发布的对象(新浪和腾讯)
NewsCompany *company = [[NewsCompany alloc] init];
company.name = @"腾讯新闻";
NewsCompany *sian = [[NewsCompany alloc] init];
sian.name = @"新浪新闻";
//初始化两个人
Person *zhansan = [[Person alloc] init];
zhansan.name = @"张三";
Person *lisi = [[Person alloc] init];
lisi.name = @"李四";
//模拟发布通知
//初始化通知中心
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
//注册通知监听器
/**
* 注册一个监听通知的监听器
*
* @param observer 监听器,即谁要接收这个通知
* @param aSelector 收到通知后,回调监听器这个方法,并且把通知对象当做参数传入
* @param aName 通知的名称,如果为nil,那么无论通知名称是什么,监听器都能收到这个通知
* @param anObject 通知发布者(如果为nil,不关心是谁发布的通知,可以更具通知的名称来获得哪条通知,如果aName和anObject都为nil)
*/
// - (void)addObserver:(id)observer selector:(SEL)aSelector name:(nullable NSString *)aName object:(nullable id)anObject;
//注册一个张三要接收军事新闻的监听器,接收到消息后会调用- (void)newCome:(NSNotification *)note方法
[center addObserver:zhansan selector:@selector(newCome:) name:@"junshi_new_come" object:nil];
[center addObserver:lisi selector:@selector(newCome:) name:@"gaoxiao_new_come" object:nil];
//发布通知
//腾讯发布了一侧通知
[center postNotificationName:@"junshi_new_come" object:company userInfo:@{@"title":@"哈哈哈哈哈我的武器好厉害",@"intro":@"哈哈哈哈哈我的武器好厉害......"}];
//新浪发布了一条搞笑新闻
[center postNotificationName:@"gaoxiao_new_come" object:sian userInfo:@{@"title":@"哈哈哈太搞笑了"}];
//然后运行工程打印如下:
2016-09-12 22:08:07.552 通知的使用[1748:85334] 张三接收到腾讯新闻的通知,通知内容是:{
intro = "\U4f0a\U62c9\U514b\U6218\U4e89\U505c\U6b62\U4e86......";
title = "\U4f0a\U62c9\U514b\U6218\U4e89\U505c\U6b62\U4e86";
}
2016-09-12 22:08:07.552 通知的使用[1748:85334] 李四接收到新浪新闻的通知,通知内容是:{
title = "\U54c8\U54c8\U54c8\U592a\U641e\U7b11\U4e86";
}
//证明张三和李四都接收到了各自喜爱的新闻
注意事项
- 在通知中心注册过的对象,必须在该对象释放前取消注册。否则,当相应的通知再次出现时,通知中心仍然会向该监听器发送消息。因为相应的监听器对象已经被释放了,所以可能会导致应用崩溃
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- 执行顺序:一定要先向通知中心注册通知监听器,也就是谁要监听谁发布的消息,然后再执行发布消息,不然会导致消息发出来了没人接收的情况
通知的使用方法二:
使用Block的方法监听通知:
- (id <NSObject>)addObserverForName:(nullableNSString *)name object:(nullableid)obj queue:(nullableNSOperationQueue *)queue usingBlock:(void (^)(NSNotification *note))block NS_AVAILABLE(10_6, 4_0);
@interface ViewController ()
@property (nonatomic, weak) id observe;
@end
- (void)test2 {//监听通知方式二:
//1.监听通知
/**
* 监听通知
*
* Name:通知名称
object:谁发出的通知
queue:队列(决定block在哪个线程中区执行,传入nil:在发布通知的线程中去执行,也就是发布通知在哪个线程,block就在哪个线程中区执行)
usingBlock:监听到通知的block回调
注意:一定要移除
*/
_observe = [[NSNotificationCenter defaultCenter] addObserverForName:@"name" object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
//只要监听到通知 就会调用
NSLog(@"%@",[NSThread currentThread]);
}];
//2.发送通知
/**
* Name:通知名字
object:谁发出的通知
*/
[[NSNotificationCenter defaultCenter] postNotificationName:@"note" object:nil];
}
//方式二:移除通知
- (void)dealloc {
[[NSNotificationCenterdefaultCenter] removeObserver:_observe];
}
二、通知在异步线程中的使用
异步监听通知方法一:
- (void)test3{
//方法一:异步监听通知
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reciveNote) name:@"note" object:nil];
});
}
//防止先发送通知,后监听通知,导致接收不到通知,这里采用延迟发送通知(点击屏幕后再发送通知)
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
//2.发送通知
/**
* Name:通知名字
object:谁发出的通知
*/
[[NSNotificationCenter defaultCenter] postNotificationName:@"note" object:nil];
}
/**
* 监听到通知就会调用
异步:监听通知 主线程:发出通知
//总结:接收通知代码,由发布通知线程决定
*/
- (void)reciveNote {
//注意点:如果是在异步发送通知,如果需要更新UI,为了安全起见,需要回到主线程更新UI
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"%@",[NSThread currentThread]);
//打印结果:2016-09-18 22:59:42.915 通知-多线程使用[1748:87249] <NSThread: 0x7fcff0c05b40>{number = 1, name = main}
});
}
- (void)dealloc {
//方式一:移除通知
[[NSNotificationCenter defaultCenter] removeObserver:self];
异步监听通知方法二:
- (void)test4 {//异步通知方式二:
//1.监听通知
//queue:[NSOperationQueue mainQueue]即使发送通知在异步,block也会在主线程中执行,所以为了安全起见queue:一般是使用主队列
_observe = [[NSNotificationCenter defaultCenter] addObserverForName:@"note" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
//只要监听到通知 就会调用
NSLog(@"%@",[NSThread currentThread]);
}];
//2.发送通知
/**
* Name:通知名字
object:谁发出的通知
*/
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:@"note" object:nil];
});
}
- (void)dealloc {
//方式二:移除通知
[[NSNotificationCenter defaultCenter] removeObserver:_observe];
}
网友评论