iOS 協議(protocol) 和通知(NSNotification)一般人不知道的點

語言: CN / TW / HK

這是我參與11月更文挑戰的第17天,活動詳情查看:2021最後一次更文挑戰

協議(protocol)

關於協議的一些定義,簡單使用方法就不多説了.

協議添加添加屬性

一般人可能不知道,協議除了可以添加方法以外,還可以添加屬性,當一個對象遵守了協議後,他就也擁有了協議中的屬性

需要注意的是,協議中的屬性是沒有getter/setter方法的,需要我們使用關鍵字@synthesize聲明需要系統合成getter/setter方法。

關於協議添加屬性來舉個例子: ```

import

@protocol PersonProtocol @property (nonatomic, strong) NSString *name;//協議中的屬性 @end

@interface Person : NSObject @property (nonatomic, weak) id delegade; @end ```

找個類實現協議 ```

import "Student.h"

@interface Student () @end

@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]); } ```

打印: ``` 發送通知前 發送通知後 接收到通知了{number = 1, name = main}

```

將通知加入到隊列的方法有個枚舉參數: typedef NS_ENUM(NSUInteger, NSPostingStyle) { NSPostWhenIdle = 1, // 當runloop處於空閒狀態時post NSPostASAP = 2, // 噹噹前runloop完成之後立即post NSPostNow = 3 // 立即post,同步(會立即執行) }; 指定枚舉參數後, 隊列會根據type, 在合適的時機將NSNotification 發送到NSNotificationCenter,這就達到了異步執行的效果.

NSPostWhenIdleNSPostASAP差不多, 都會異步執行,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 時,不會合並通知