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 時,不會合並通知