1.首先通知中心和通知是两码事.
通知中心是一个类---NSNotificationCenter,通知是另一个类---NSNotification.
NSNotification是对一个通知的描述,即一个通知应该包括哪些信息.哪些行为.
通知有三个属性
@property (readonly, copy) NSString *name;通知的名字.(放假通知) @property (nullable, readonly, retain) id object;通知的发布者.(班主任) @property (nullable, readonly, copy) NSDictionary *userInfo;通知的具体信息.(什么时候放假,什么时候收假,放假期间是否有作业,放假不要到河边玩)
初始化有两个方法
- (instancetype)initWithName:(NSString *)name object:(nullable id)object userInfo:(nullable NSDictionary *)userInfo NS_AVAILABLE(10_6, 4_0) NS_DESIGNATED_INITIALIZER; - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder NS_DESIGNATED_INITIALIZER;
通知有一个分类---NSNotificationCreation,用于创建通知,其实就是快速创建通知方法.
该分类有三个方法:
+ (instancetype)notificationWithName:(NSString *)aName object:(nullable id)anObject;//创建一个通知,包含通知的名称,通知的发布者 + (instancetype)notificationWithName:(NSString *)aName object:(nullable id)anObject userInfo:(nullable NSDictionary *)aUserInfo;//创建一个通知,包含通知的名称,通知的发布者,通知的具体信息 - (instancetype)init /*NS_UNAVAILABLE*/; /* do not invoke; not a valid initializer for this class */ 该方法不可用,不能被调用,对于通知这个类来说不是一个有效的初始化方法
2.通知中心
通知中心其实就是不同对象间通信的中间人.比如有对象A,B.想要实现A,B对象间的通信,信息传递,就可以使用通知中心实现.A通过通知中心的POST方法发布通知,B通过通知中心的addObserver方法可以接收通知;
有些地方说每一个应用程序都内置了一个NSNotificationCenter对象.意思是UIApplication对象有一个NSNotificationCenter类型的属性.?然而查看UIApplication类,并没有这个属性.通过查询官方文档,可知每一个运行中的Cocoa应用程序默认有一个NSNotificationCenter对象,"Each running Cocoa program has a default notification center.";
作用范围:NSNotificationCenter只能在一个应用程序中实现消息的传递,如果希望在不同程序中实现消息传递,苹果官方建议使用---NSDistributedNotificationCenter
.
"An NSNotificationCenter
object can deliver notifications only within a single program. If you want to post a notification to other processes or receive notifications from other processes, use an instance of NSDistributedNotificationCenter
."
3.通知中心的属性
@package void * __strong _impl; void * __strong _callback; void *_pad[11];
??package的权限还是不太清楚
??这几个属性啥意思??回头查,这里不是重点
4.通知中心的方法
>1获得通知中心
+ (NSNotificationCenter *)defaultCenter;
>2.添加通知的接收者
- (void)addObserver:(id)observer selector:(SEL)aSelector name:(nullable NSString *)aName object:(nullable id)anObject;
参数含义:
observer:通知的接收者.某个通知由谁来接收(程序狗--我)
aSelector:接收者接收到通知后调用的方法(写代码);会把通知对象当参数传递
name:通知的名称.(做微信项目);如果为nil,可以接受到anObject发布的任何通知
anObject:通知的发布者.(老大);如果为nil,可以接收到任何对象的通知
如果name和anObject都为nil,observer可以接受到所有通知.
方法大意:"程序狗(我)"在接收到"老大"发布的"做微信项目"的通知后就会调用自己的"写代码"方法,
>3.通知的发布
- (void)postNotification:(NSNotification *)notification;//发布一个通知
- (void)postNotificationName:(NSString *)aName object:(nullable id)anObject; //发布一个通知,包括通知的发布者,通知的名字
- (void)postNotificationName:(NSString *)aName object:(nullable id)anObject userInfo:(nullable NSDictionary *)aUserInfo;//发布一个通知,包括通知的发布者,通知的名字,通知的具体信息
>4.移除接收者
- (void)removeObserver:(id)observer;//移除接收者,observer:要移除的接收者
- (void)removeObserver:(id)observer name:(nullable NSString *)aName object:(nullable id)anObject;//移除observer收到的关于anObject发布的名为aName的通知.
>5.添加接收者(2)
- (id <NSObject>)addObserverForName:(nullable NSString *)name object:(nullable id)obj queue:(nullable NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *note))block NS_AVAILABLE(10_6, 4_0); // The return value is retained by the system, and should be held onto by the caller in // order to remove the observer with removeObserver: later, to stop observation.
参数含义:
name:通知的名字
obj:通知的发布者
queue:接收到通知后,block执行所在的队列
block:接收到通知调用的代码段
5.注意:
1>当通知的接收者被释放时,必须移除接收者(调用移除接收者方法):
- (void)removeObserver:(id)observer;
- (void)removeObserver:(id)observer name:(nullable NSString *)aName object:(nullable id)anObject;
就是说,如果接收者释放了,但是没有被移除,那么通知中心还会向接收者发送通知,这就是访问已经被释放的对象,就是野指针访问,故而在MRC机制下需要重写dealloc方法,在该方法中移除接收者.
6.一些可能会经常用到的通知
>1.UIDevice通知
UIDevice,简单地说就是用于描述当前设备的对象.通过该类可以获取当前设备的一些配置信息,比如设备的版本号,设备名称,型号,操作系统.电池状态.
UIDevice对象会不间断的发布一些通知:
UIDeviceOrientationDidChangeNotification //设备方向改变
UIDeviceBatteryStateDidChangeNotification //电池状态改变
UIDeviceBatteryLevelDidChangeNotification // 电池电量改变
UIDeviceProximityStateDidChangeNotification // 近距离传感器,,接近某些东西的状态改变
>2.键盘的通知
UIKeyboardWillShowNotification;//键盘将要出现
UIKeyboardDidShowNotification;//键盘已经出现
UIKeyboardWillHideNotification;//键盘将要隐藏
UIKeyboardDidHideNotification;//键盘已经隐藏
UIKeyboardWillChangeFrameNotification //键盘将要改变位置
UIKeyboardDidChangeFrameNotification //键盘已经改变位置
键盘的通知会附带一些具体信息:userInfo
UIKeyboardFrameBeginUserInfoKey //键盘位置改变前的frame
UIKeyboardFrameEndUserInfoKey //键盘位置改变后的frame
UIKeyboardAnimationDurationUserInfoKey //键盘位置改变的动画时间
UIKeyboardAnimationCurveUserInfoKey //键盘动画执行的节奏(快慢)????
UIKeyboardIsLocalUserInfoKey
UIKeyboardCenterBeginUserInfoKey
UIKeyboardCenterEndUserInfoKey
UIKeyboardBoundsUserInfoKey
7.通知和代理之间的异同:
相同:
都可以实现对象间数据,消息传递,通信
不同:
代理需要告诉确定的对象发生了什么,通知不需要,一个对象发布通知,根本不用管谁会接收到这个通知.
8.示例代码
#import <Foundation/Foundation.h> #import "Boss.h" #import "Me.h" #import "Boss2.h" #import "Someone.h" //boss(腾讯老大)的通知 static NSString *const WeChatDevelop = @"微信项目开发"; static NSString *const QQDevelop = @"QQ项目开发"; //boss2(新浪老大)的通知 static NSString *const WeiBoDevelop = @"微博项目开发"; static NSString *const SinaReaderDevelop = @"新浪读书项目开发"; int main(int argc, const char * argv[]) { @autoreleasepool { //创建通知的发布者和接收者 Boss *boss = [[Boss alloc]init]; boss.name = @"腾讯"; Boss2 *boss2 = [[Boss2 alloc]init]; boss2.name = @"新浪"; Me *me = [[Me alloc]init]; me.name = @"王大锤"; Someone *someone = [[Someone alloc]init]; someone.name = @"二狗子"; //1.获取通知中心 NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; // 逗比程序员成为通知接收者 // 我成为腾讯的扣扣项目的接收者 [notificationCenter addObserver:me selector:@selector(writeQQ:) name:nil object:boss];
// someone成为微博项目接收者 [notificationCenter addObserver:someone selector:@selector(writeWeiBo:) name:WeiBoDevelop object:boss2]; // 2.老板发布通知 // 腾讯发布通知 [notificationCenter postNotificationName:WeChatDevelop object:boss userInfo:@{@"老板":boss.name,@"项目名称":@"微信开发"}]; [notificationCenter postNotificationName:QQDevelop object:boss userInfo:@{@"老板":boss.name,@"项目名称":@"QQ开发"}]; // 新浪发布通知 [notificationCenter postNotificationName:WeiBoDevelop object:boss2 userInfo:@{@"老板":boss.name,@"项目名称":@"微博开发"}]; [notificationCenter postNotificationName:SinaReaderDevelop object:boss2 userInfo:@{@"老板":boss.name,@"项目名称":@"新浪读书开发"}]; } return 0; }
控制台输出取决于添加接收者代码:
// 我成为腾讯的扣扣项目的接收者 [notificationCenter addObserver:me selector:@selector(writeQQ:) name:nil object:boss]; 可以接收到boss发出的所有通知 [notificationCenter addObserver:me selector:@selector(writeQQ:) name:nil object:nil]; 可以接受到boss,boss2(如果有其他对象也可以)发出的所有通知. // someone成为微博项目接收者 [notificationCenter addObserver:someone selector:@selector(writeWeiBo:) name:WeiBoDevelop object:boss2]; 可以接收到boss2的微博开发的通知
9.通知的本质
个人想法:
程序最底层是函数,方法(都是具有特定功能的代码段)的调用.
假设有对象A,B和通知中心;
A通过通知中心发布通知,调用post方法,意味着,将传入的参数,设置给NSNotification的属性(我猜测是不是这样),主要的用userInfo记录著需要传递的数据.那么add方法是如何将post方法中传入的数据传递给接收者呢?