IOS 通知+非同步通知詳解
阿新 • • 發佈:2019-01-08
一、通知的基本使用
每一個應用程式都有一個通知中心,專門負責協助不同 物件之間的訊息通訊。
任何一個物件都可以向通知中心釋出通知,描述自己在做什麼。其他感興趣的物件可以申請在某個特定通知釋出時(或在某個特定的物件釋出通知時)收到這個通知。
//一個通知一般包含三個屬性:
@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];
}