iOS 協議(protocol) 和通知(NSNotification)一般人不知道的點
這是我參與11月更文挑戰的第17天,活動詳情查看:2021最後一次更文挑戰
協議(protocol)
關於協議的一些定義,簡單使用方法就不多説了.
協議添加添加屬性
一般人可能不知道,協議除了可以添加方法以外,還可以添加屬性,當一個對象遵守了協議後,他就也擁有了協議中的屬性
需要注意的是,協議中的屬性是沒有getter/setter方法的,需要我們使用關鍵字
@synthesize
聲明需要系統合成getter/setter方法。
關於協議添加屬性來舉個例子: ```
import
@protocol PersonProtocol
@interface Person : NSObject
@property (nonatomic, weak) id
找個類實現協議 ```
import "Student.h"
@interface Student ()
@implementation Student //協議裏的屬性 @synthesize name;
@end
應用以下:
Person onePerson = [Person new];
Student xiaoming = [Student new];
onePerson.delegade = xiaoming;
onePerson.delegade.name = @"xiaoming";
NSLog(@"%@",xiaoming.name);
```
打印結果如下
xiaoming
通知(NSNotification)
先來看下常用的發通知的套路
發送:
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSLog(@"要發通知啦");
[[NSNotificationCenter defaultCenter] postNotificationName:@"aaa" object:nil];
NSLog(@"通知發完啦");
}
接收:
```
- (BOOL)application:(UIApplication )application didFinishLaunchingWithOptions:(NSDictionary )launchOptions {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(testNoti) name:@"aaa" object:nil];
return YES;
}
- (void)testNoti { NSLog(@"收到通知啦 %@",[NSThread currentThread]); } ```
看下打印:
要發通知啦
收到通知啦 <NSThread: 0x17406d880>{number = 1, name = main}
通知發完啦
總結:
通過
postNotificationName:
發送通知是同步的, 會卡住當前線程. 就是説, 發送通知後,會等到對方接收到通知並執行完收到通知的方法後才會接着往下走.
關於移除通知
iOS 9以後UIViewController 添加通知後可以不用移除, 系統會自動給移除.
異步發送通知
異步發送通知需要三步 1. 創建通知(NSNotification) 2. 創建通知隊列(NSNotificationQueue) 3. 將通知放入隊列中執行
發送:
NSLog(@"發送通知前");
//創建通知
NSNotification *noti = [[NSNotification alloc] initWithName:@"aaa" object:nil userInfo:nil];
//將通知加入隊列,並設置為NSPostASAP,噹噹前runloop完成之後立即post
[[NSNotificationQueue defaultQueue] enqueueNotification:noti postingStyle:NSPostASAP];
NSLog(@"發送通知後");
接收: ``` - (BOOL)application:(UIApplication )application didFinishLaunchingWithOptions:(NSDictionary )launchOptions {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(testNoti) name:@"aaa" object:nil];
return YES;
}
- (void)testNoti { NSLog(@"接收到通知了%@",[NSThread currentThread]); } ```
打印:
```
發送通知前
發送通知後
接收到通知了
```
將通知加入到隊列的方法有個枚舉參數:
typedef NS_ENUM(NSUInteger, NSPostingStyle) {
NSPostWhenIdle = 1, // 當runloop處於空閒狀態時post
NSPostASAP = 2, // 噹噹前runloop完成之後立即post
NSPostNow = 3 // 立即post,同步(會立即執行)
};
指定枚舉參數後, 隊列會根據type, 在合適的時機將NSNotification 發送到NSNotificationCenter,這就達到了異步執行的效果.
NSPostWhenIdle
和NSPostASAP
差不多, 都會異步執行,NSPostNow
會立即執行
通知合併
將通知放入隊列執行還有另外一個方法:
- (void)enqueueNotification:(NSNotification *)notification postingStyle:(NSPostingStyle)postingStyle coalesceMask:(NSNotificationCoalescing)coalesceMask forModes:(nullable NSArray<NSRunLoopMode> *)modes;
方法的第二個參數:(NSNotificationCoalescing)coalesceMask
就是控制通知的合併策略.
如下:
typedef NS_OPTIONS(NSUInteger, NSNotificationCoalescing) {
NSNotificationNoCoalescing = 0, // 不合成
NSNotificationCoalescingOnName = 1, // 根據NSNotification的name字段進行合成
NSNotificationCoalescingOnSender = 2 // 根據NSNotification的object字段進行合成
};
發送:
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSLog(@"發送通知前");
NSNotification *noti = [[NSNotification alloc] initWithName:@"aaa" object:nil userInfo:nil];
[[NSNotificationQueue defaultQueue] enqueueNotification:noti postingStyle:NSPostASAP];
[[NSNotificationQueue defaultQueue] enqueueNotification:noti postingStyle:NSPostWhenIdle];
[[NSNotificationQueue defaultQueue] enqueueNotification:noti postingStyle:NSPostWhenIdle coalesceMask:NSNotificationCoalescingOnName forModes:nil];
NSLog(@"發送通知後");
}
接收: ``` - (BOOL)application:(UIApplication )application didFinishLaunchingWithOptions:(NSDictionary )launchOptions {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(testNoti) name:@"aaa" object:nil];
return YES;
}
- (void)testNoti { NSLog(@"接收到通知了%@",[NSThread currentThread]); } ```
打印:
發送通知前
發送通知後
接收到通知了<NSThread: 0x280fbee40>{number = 1, name = main}
可以看到發了三個通知,最後卻收到了一條,説明,通知進行和合並。
注意, 如果直接使用postNotificationName:或者指定NSPostNow提交方式或者指定合併策略為NSNotificationNoCoalescing 時,不會合並通知