前言
最近看了下QTEventBus的源码,防止遗忘,写下来巩固一下。水平不太行,看的也比较浅
另外本文不太设计QTEventBus中的消息(其实是我没看)
使用
QTEventBus使用比较简单,主要是QTEventBus.h中的方法
- 添加监听
//监听全局总线,监听的生命周期和object一样
#define QTSub(_object_,_className_) ((QTEventSubscriberMaker<_className_ *> *)[_object_ subscribeSharedBus:[_className_ class]])
#define QTSubName(_object_,_name_) ([_object_ subscribeSharedBusOfName:_name_])
//监听全局总线,异步在主线程监听
#define QTSubMain(_object_,_className_) ([QTSub(_object_, _className_) atQueue:dispatch_get_main_queue()])
//全局总线监听NSNotification
#define QTSubNoti(_object_,_name_) ((QTEventSubscriberMaker<NSNotification *> *)[_object_ subscribeNotification:_name_])
//全局总线监听QTJsonEvent
#define QTSubJSON(_object_,_name_) ((QTEventSubscriberMaker<QTJsonEvent *> *)[_object_ subscribeSharedBusOfJSON:_name_])
- 发布消息
/**
发布Event,等待event执行结束
*/
- (void)dispatch:(id<QTEvent>)event;
/**
异步到eventbus内部queue上dispath
*/
- (void)dispatchOnBusQueue:(id<QTEvent>)event;
/**
异步到主线程dispatch
*/
- (void)dispatchOnMain:(id<QTEvent>)event;
订阅
订阅的宏定义中,除了通知之外,作者一共提供了4个宏定义。而实际上这四个宏定义中,QTSub是基础,其他3个都是在此基础上的补充。首先我们看一下QTSub都做了些什么。
QTSub()实际上就是创建监听者(可以这么理解,但是这一步创建的并非最终的监听者),我们先看一下QTEventSubscriberMaker
/**
内存中保存的监听者
*/
@interface QTEventSubscriberMaker()
- (instancetype)initWithEventBus:(QTEventBus *)eventBus
eventClass:(Class)eventClass;
@property (strong, nonatomic) Class eventClass;
@property (strong, nonatomic) NSObject * lifeTimeTracker;
@property (strong, nonatomic) dispatch_queue_t queue;
@property (strong, nonatomic) NSMutableArray * eventSubTypes;
@property (strong, nonatomic) QTEventBus * eventBus;
@property (copy, nonatomic) void(^hander)(__kindof NSObject *);
@end
我们逐一看一下QTEventSubscriberMaker的属性
- eventClass
这是类名,需要被监听对象的类型
因为是类名为关键字,这就导致了子类的通知父类是无法接收到的
- lifeTimeTracker
这是自动释放监听者的工具
- queue
监听回调的线程。默认为空
- eventSubTypes
这是一个二级事件。后续会讲
- eventBus
单例。管理监听者,发布通知
- hander
回调
创建监听者
这里可能有点歧义,只是为了方便理解,这一步创建的并非最终的监听者,只是一个临时变量
OK,我们看回到QTSub(),我们可以看到,QTSub()实际上是调用这样一个方法
/**
在EventBus单例shared上监听指定类型的事件,并且跟随self一起取消监听
*/
- (QTEventSubscriberMaker *)subscribeSharedBus:(Class)eventClass{
return [QTEventBus shared].on(eventClass).freeWith(self);
}
继续看一下on(eventClass),这里是block的链式编程,这块我不太熟,就不展开了,后续继续学习
- (QTEventSubscriberMaker<id> *(^)(Class eventClass))on{
return ^QTEventSubscriberMaker *(Class eventClass){
return [[QTEventSubscriberMaker alloc] initWithEventBus:self
eventClass:eventClass];
};
}
可以看到,在该方法中一共两个参数。self和eventClass
首先该方法是EventBus的实例方法, 所以这里的self就是指EventBus,我们还可以看到,EventBus实际上是一个单例
+ (instancetype)shared{
static QTEventBus * _instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[QTEventBus alloc] init];
});
return _instance;
}
另外一个就是类型。我们暂时先不管保存类型是干什么用的。到这里,监听者就创建好了。
监听者完善
虽然到这一步监听已经创建好了,不过在 QTEventSubscriberMaker 还有其他几个方法我们可以看一下
- (QTEventSubscriberMaker *)atQueue:(dispatch_queue_t)queue{
return self.atQueue(queue);
}
调用atQueue就是使我们的回调block在我们制定的队列去执行
- (QTEventSubscriberMaker *)freeWith:(id)object{
return self.freeWith(object);
}
自动释放,后面讲
- (QTEventSubscriberMaker *)ofSubType:(NSString *)eventType{
return self.ofSubType(eventType);
}
添加二级事件,后面讲
- (id<QTEventToken>)next:(QTEventNextBlock)hander{
return self.next(hander);
}
保存block回调和监听者,下面讲
保存监听者
既然创建好了监听者,第二步肯定就是保存了。QTEventBus是如何保存监听者的呢,我们看一下作者的示例
[QTSub(self, DemoEvent) next:^(DemoEvent *event) {
NSLog(@"%ld",event.count);
}];
我们可以看到,紧着跟QTSub的是next。而保存监听者实际上就是在这一步中做的
- (id<QTEventToken>(^)(void(^)(id event)))next{
return ^id<QTEventToken>(void(^hander)(__kindof NSObject * event)){
self.hander = hander;
return [self.eventBus _createNewSubscriber:self];
};
}
先保存了block。然后调用了_createNewSubscriber
- (id<QTEventToken>)_createNewSubscriber:(QTEventSubscriberMaker *)maker{
if (!maker.hander) {
return nil;
}
if (maker.eventSubTypes.count == 0) {//一级事件
_QTEventToken * token = [self _addSubscriberWithMaker:maker eventType:nil];
return token;
}
NSMutableArray * tokens = [[NSMutableArray alloc] init];
for (NSString * eventType in maker.eventSubTypes) {
_QTEventToken * token = [self _addSubscriberWithMaker:maker eventType:eventType];
[tokens addObject:token];
}
_QTComposeToken * token = [[_QTComposeToken alloc] initWithTokens:tokens];
return token;
}
我们先不考虑二级事件。先说一级事件。我们继续看一下_addSubscriberWithMaker方法
- (_QTEventToken *)_addSubscriberWithMaker:(QTEventSubscriberMaker *)maker eventType:(NSString *)eventType{
__weak typeof(self) weakSelf = self;
NSString * eventKey = __generateUnqiueKey(maker.eventClass, eventType);
NSString * groupId = [self.prefix stringByAppendingString:eventKey];
NSString * uniqueId = [groupId stringByAppendingString:@([NSDate date].timeIntervalSince1970).stringValue];
_QTEventToken * token = [[_QTEventToken alloc] initWithKey:uniqueId];
BOOL isCFNotifiction = (maker.eventClass == [NSNotification class]);
if (eventType && isCFNotifiction) {
[self _addNotificationObserverIfNeeded:eventType];
}
token.onDispose = ^(NSString *uniqueId) {
__strong typeof(self) strongSelf = weakSelf;
if (!strongSelf) {
return;
}
BOOL empty = [strongSelf.collection removeUniqueId:uniqueId ofKey:groupId];
if (empty && isCFNotifiction) {
[strongSelf _removeNotificationObserver:eventType];
}
};
//创建监听者
_QTEventSubscriber * subscriber = [[_QTEventSubscriber alloc] init];
subscriber.queue = maker.queue;
subscriber.handler = maker.hander;
subscriber.uniqueId = uniqueId;
if (maker.lifeTimeTracker) {
[maker.lifeTimeTracker.eb_disposeBag addToken:token];
}
[self.collection addObject:subscriber forKey:groupId];
return token;
}
看着很复杂的样子,其实不复杂,一步一步看
创建关键字
__generateUnqiueKey字面上的意思就是创建一个唯一标识符
static inline NSString * __generateUnqiueKey(Class<QTEvent> cls,NSString * eventType){
Class targetClass = [cls respondsToSelector:@selector(eventClass)] ? [cls eventClass] : cls;
if (eventType) {
return [NSString stringWithFormat:@"%@_of_%@",eventType,NSStringFromClass(targetClass)];
}else{
return NSStringFromClass(targetClass);
}
}
看完源码之后,确实如此。不过这里有一个细节就是先判断一下需要监听的类是否实现了eventClass方法,如果是则使用该方法的返回值而非类名。这个主要是防止用户使用NSNotification和NSString的子类,然后订阅之后接收不到消息。看一下作者在NSString和NSNotification的分类中做了什么
@implementation NSString (QTEevnt)
- (NSString *)eventSubType{
return [self copy];
}
+ (Class)eventClass{
return [NSString class];
}
@end
@implementation NSNotification (QTEvent)
+ (Class)eventClass{
return [NSNotification class];
}
- (NSString *)eventSubType{
return self.name;
}
@end
同样的。我们自定义的类,也可以在根类中实现eventClass,从而保证父类以及子类都能接收到通知
做完这一步就是根据类名创建标识符了。eventType是二级事件。虽然先不考虑,但是在这里我们还是需要了解一下,一级事件就是以类名作为关键字,而二级事件是eventType_of_类名
我们可以看到,上一步创建的是eventKey,作者根据eventKey创建了grounpId,和uniqueId
groupId = 时间 + eventKey
uniqueId = groupId + 时间
然后根据uniqueId创建了一个Token(用于取消监听)
再然后就是个根据Maker创建监听者并保存。这里还有两个细节
- lifeTimeTracker
自动释放监听者,最后再说,先不看
仅需要了解在这一步创建了一个token,添加到了eb_disposeBags属性中
- QTEventBusCollection
我们可以看到,作者是将监听者添加到这样一个collection中了,这里就不展开讲了
collection其实就是一个双向链表
根据groupId创建一个链表,若存在该链表就继续往后添加。其实就是将同一个类的一级监听或同一个二级监听放在一个链表上
再将链表保存到一个字典中,groupid作为关键字
到这里呢,监听者就创建并保存好了,下一步就是发布消息了
发消息
作者一共提供了3中发布消息的方式,我们主要看第一个方法
我们详细看一下第一个方法
- (void)dispatch:(id<QTEvent>)event{
if (!event) {
return;
}
NSString * eventSubType = [event respondsToSelector:@selector(eventSubType)] ? [event eventSubType] : nil;
if (eventSubType) {
//二级事件
NSString * key = __generateUnqiueKey(event.class, eventSubType);
[self _publishKey:key event:event];
}
//一级事件
NSString * key = __generateUnqiueKey(event.class, nil);
[self _publishKey:key event:event];
}
首先是判断是否需要发送二级事件,若有则发送,若无则跳过。二级事件我们暂先不考虑。
然后就是发送一级事件。继续看源码
- (void)_publishKey:(NSString *)eventKey event:(NSObject *)event{
NSString * groupId = [self.prefix stringByAppendingString:eventKey];
NSArray * subscribers = [self.collection objectsForKey:groupId];
if (!subscribers || subscribers.count == 0) {
return;
}
for (_QTEventSubscriber * subscriber in subscribers) {
if (subscriber.queue) { //异步分发
dispatch_async(subscriber.queue, ^{
if (subscriber.handler) {
subscriber.handler(event);
}
});
}else{ //同步分发
if (subscriber.handler) {
subscriber.handler(event);
}
}
}
}
首先根据groupId取出所有一级事件的监听者,然后遍历调用。
到这里,就完成整个流程了。
发送消息扩展
- (void)dispatchOnBusQueue:(id<QTEvent>)event{
dispatch_async(self.publishQueue, ^{
[self dispatch:event];
});
}
- (void)dispatchOnMain:(id<QTEvent>)event{
if ([NSThread isMainThread]) {
[self dispatch:event];
}else{
dispatch_async(dispatch_get_main_queue(), ^{
[self dispatch:event];
});
}
}
可以看到这两个方法一个是在作者定义的队列上发送消息,另外一个实在主线程执行。
不过要特别注意的是,如果在创建监听者时指定了队列,那么这边的设置将不起作用
if (subscriber.queue) { //异步分发
dispatch_async(subscriber.queue, ^{
if (subscriber.handler)
subscriber.handler(event);
}
});
}
可以看到最终还是在制定的队列上执行回调
二级事件
前面我们一直没有说到二级事件,那么我们现在可以说一说二级事件了。
我们再看一下QTEventSubscriberMaker的方法,可以看到有这样一个方法
- (QTEventSubscriberMaker<id> *(^)(NSString *))ofSubType{
return ^QTEventSubscriberMaker *(NSString * eventType){
if (!eventType) {
return self;
}
@synchronized(self) {
[self.eventSubTypes addObject:eventType];
}
return self;
};
}
即调用ofSubType就是添加key值到数组中。然后在_createNewSubscriber方法中,会逐一将这些二级事件保存到collection中去。
NSMutableArray * tokens = [[NSMutableArray alloc] init];
for (NSString * eventType in maker.eventSubTypes) {
_QTEventToken * token = [self _addSubscriberWithMaker:maker eventType:eventType];
[tokens addObject:token];
}
_QTComposeToken * token = [[_QTComposeToken alloc] initWithTokens:tokens];
最后在dispatch时,根据参数中的eventSubType的来确定是否要发送二级事件以及发送哪个二级事件。
NSString * eventSubType = [event respondsToSelector:@selector(eventSubType)] ? [event eventSubType] : nil;
if (eventSubType) {
//二级事件
NSString * key = __generateUnqiueKey(event.class, eventSubType);
[self _publishKey:key event:event];
}
值得注意的是:
- 即使发送了二级事件,还是会再发送一次一级事件。
- 如果调用了ofSubType方法,那么此处的订阅就是一个二级事件了,不再会触发一级事件。
自动释放
最后我们就来看看QTEventBus是如何做到自动释放的,以subscribeSharedBus为例,其他方法都一样
- (QTEventSubscriberMaker *)subscribeSharedBus:(Class)eventClass{
return [QTEventBus shared].on(eventClass).freeWith(self);
}
我们可以注意到,最后调用了一个freeeWith(self),继续看源码
- (QTEventSubscriberMaker<id> *(^)(id))freeWith{
return ^QTEventSubscriberMaker *(id lifeTimeTracker){
self.lifeTimeTracker = lifeTimeTracker;
return self;
};
}
即将监听者赋值给maker,我们再后头看看保存监听者时做了什么
_QTEventToken * token = [[_QTEventToken alloc] initWithKey:uniqueId];
...
//创建监听者
_QTEventSubscriber * subscriber = [[_QTEventSubscriber alloc] init];
subscriber.queue = maker.queue;
subscriber.handler = maker.hander;
subscriber.uniqueId = uniqueId;
if (maker.lifeTimeTracker) {
[maker.lifeTimeTracker.eb_disposeBag addToken:token];
}
在监听者中添加了token.那我们就看一下eb_disposeBag做了什么
- (NSMutableArray<id<QTEventToken>> *)tokens{
if (!_tokens) {
_tokens = [[NSMutableArray alloc] init];
}
return _tokens;
}
- (void)addToken:(id<QTEventToken>)token{
@synchronized(self) {
[self.tokens addObject:token];
}
}
- (void)dealloc{
@synchronized(self) {
for (id<QTEventToken> token in self.tokens) {
if ([token respondsToSelector:@selector(dispose)]) {
[token dispose];
}
}
}
}
可以看到监听者保存了所有的一级事件和二级事件的token,当监听者被释放时,调用了token的dispose方法
- (void)dispose{
@synchronized(self){
if (_isDisposed) {
return;
}
_isDisposed = YES;
}
if (self.onDispose) {
self.onDispose(self.uniqueId);
}
}
调用了onDispose。OK,继续回头看在保存监听者时做了什么
token.onDispose = ^(NSString *uniqueId) {
__strong typeof(self) strongSelf = weakSelf;
if (!strongSelf) {
return;
}
BOOL empty = [strongSelf.collection removeUniqueId:uniqueId ofKey:groupId];
if (empty && isCFNotifiction) {
[strongSelf _removeNotificationObserver:eventType];
}
};
可以看到最终从collection中移除了该事件的监听