版本记录
版本号 | 时间 |
---|---|
V1.0 | 2017.07.17 |
前言
与代理相比,通知具有低耦合的特点,两个毫无关联的控制器之间可以进行相互通信并相应操作,用了通知很久,但是从没有系统的总结一下通知相关的知识和遇到的坑,下面就讲一下通知的相关知识,先从简单的知识点和API开始。
通知基础
通知是ios中的一种消息机制,观察者只要向消息中心注册, 即可接受其他对象发送来的消息,消息发送者和消息接受者两者可以互相一无所知,完全解耦。这种消息通知机制可以应用于任意时间和任何对象,观察者可以有多个,所以消息具有广播的性质,只是需要注意的是,观察者向消息中心注册以后,在不需要接受消息时需要向消息中心注销,这种消息广播机制是典型的“Observer”(观察者)模式。
消息机制常常用于在向服务器端请求数据或者提交数据的场景,在和服务器端成功交互后,需要处理服务器端返回的数据,或发送响应消息等,就需要用到消息机制。其原理主要如下所示:
API
下面我们看一下ios中通知相关的API。
NSNotification
/**************** Notifications ****************/
@interface NSNotification : NSObject <NSCopying, NSCoding>
@property (readonly, copy) NSNotificationName name;
@property (nullable, readonly, retain) id object;
@property (nullable, readonly, copy) NSDictionary *userInfo;
- (instancetype)initWithName:(NSNotificationName)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;
@end
@interface NSNotification (NSNotificationCreation)
+ (instancetype)notificationWithName:(NSNotificationName)aName object:(nullable id)anObject;
+ (instancetype)notificationWithName:(NSNotificationName)aName object:(nullable id)anObject userInfo:(nullable NSDictionary *)aUserInfo;
- (instancetype)init /*NS_UNAVAILABLE*/; /* do not invoke; not a valid initializer for this class */
@end
这里面有几点:
- name:通知的名字,其实就是为通知起的别名,作用就是用以区分不同通知,如果为nil标识可以接收任何名字的通知。
- object :发送通知的对象,用以区分是谁发出的通知,如果为nil,表示可以接受任何对象发送的通知。
- userInfo:它是一个字典用来存储发送的通知信息,当我们post一个通知的时候,就可以存放在字典里面,add监听端,就可以将这个userInfo取出来,得到通知的内容。
- 接下里的几个对象方法和类方法中存储的就是通知的初始化或者实例化方法。
** NSNotificationCenter**
/**************** Notification Center ****************/
@interface NSNotificationCenter : NSObject {
@package
void *_impl;
void *_callback;
void *_pad[11];
}
#if FOUNDATION_SWIFT_SDK_EPOCH_AT_LEAST(8)
@property (class, readonly, strong) NSNotificationCenter *defaultCenter;
- (void)addObserver:(id)observer selector:(SEL)aSelector name:(nullable NSNotificationName)aName object:(nullable id)anObject;
#endif
- (void)postNotification:(NSNotification *)notification;
- (void)postNotificationName:(NSNotificationName)aName object:(nullable id)anObject;
- (void)postNotificationName:(NSNotificationName)aName object:(nullable id)anObject userInfo:(nullable NSDictionary *)aUserInfo;
- (void)removeObserver:(id)observer;
- (void)removeObserver:(id)observer name:(nullable NSNotificationName)aName object:(nullable id)anObject;
- (id <NSObject>)addObserverForName:(nullable NSNotificationName)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.
@end
这里涉及到的就是通知的转发、监听以及移除等,这个后续会详细说明。
通知的发送
有关通知发送的方法主要有三个,如下:
- (void)postNotification:(NSNotification *)notification;
- (void)postNotificationName:(NSNotificationName)aName object:(nullable id)anObject;
- (void)postNotificationName:(NSNotificationName)aName object:(nullable id)anObject userInfo:(nullable NSDictionary *)aUserInfo;
我们先说一下相关参数,这里的参数和注册观察者时候的参数也都是一样的,说一遍就不多说了。
- notification:通知对象,通知中心发出的对象就是它。
- aName:通知的名字,用以区分不同通知,在注册观察者的时候,传nil表示可以监听任何名称的通知。
- anObject:发送通知的对象,如果传nil表示不关心是谁发送的通知,观察者那边传入nil表示可以接受任何发送者的通知。
- aUserInfo:通知消息,是一个字典,发送的内容可以写在里面。
第一种发送通知
//第一种发送通知
NSNotification *notification = [NSNotification notificationWithName:@"notificationTestOne" object:self];
[[NSNotificationCenter defaultCenter] postNotification:notification];
这里的object也可以为nil,表示不区分是谁发送的。
第二种发送通知
//第二种发送通知
[[NSNotificationCenter defaultCenter] postNotificationName:@"notificationTestTwo" object:self];
同上,就不多说了。
第三种发送通知
//第三种发送通知
NSDictionary *notiDict = @{@"key":@"content"};
[[NSNotificationCenter defaultCenter] postNotificationName:@"notificationTestThree" object:self userInfo:notiDict];
这里,当没有什么传递的时候,userInfo可以为空,为空的时候就和前两种发送通知是一样的了。
通知的监听
通知是一种观察者模式,有人发送就要有人observer,并调用相关方法,处理相关逻辑。下面我们就接受一下上面三种发送的通知。
第一种监听通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(processTestOne:) name:@"notificationTestOne" object:nil];
- (void)processTestOne:(NSNotification *)noti
{
NSLog(@"notificationTestOne");
}
我们看输出
2017-07-17 16:18:57.708 JJNotification[17071:1508348] notificationTestOne
可见,可以收到通知。
第二种监听通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(processTestTwo:) name:@"notificationTestTwo" object:nil];
- (void)processTestTwo:(NSNotification *)noti
{
NSLog(@"notificationTestTwo");
}
下面看输出
2017-07-17 16:24:20.773 JJNotification[17096:1537087] notificationTestTwo
可见,可以收到通知。
第三种监听通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(processTestThree:) name:@"notificationTestThree" object:nil];
- (void)processTestThree:(NSNotification *)noti
{
NSDictionary *notiDict = noti.userInfo;
NSString *content = [notiDict objectForKey:@"key"];
NSLog(@"notificationTestThree = %@",content);
}
下面看输出
2017-07-17 16:24:20.773 JJNotification[17096:1537087] notificationTestThree = content
可见,还是可以监听到通知。
通知的移除
不用的监听通知要移除,移除通知一般都是在delloc中完成,在delloc中可以移除全部监听的通知,还可以移除指定名字的通知。
移除全部通知
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
如果这么写,那么上面三个notificationTestOne
、notificationTestTwo
、notificationTestThree
通知都会被移除,可谓一劳永逸。
移除指定名字的通知
但是有的时候的需求是只要移除指定的某个通知,而保留某一个或者几个通知,具体如下所示:
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"notificationTestOne" object:nil];
}
这样子就把名字为notificationTestOne
的通知移除了,其他的通知还会起作用,保留着监听的功能。
后记
这里写的就是ios API以及通知的监听、发送以及移除等基本知识,目的就是给新手能看明白,后面的几篇我会加入稍微难一点的东西还有就是一些通知过程中碰到的坑。