QTEventBus

前言

最近看了下QTEventBus的源码,防止遗忘,写下来巩固一下。水平不太行,看的也比较浅
另外本文不太设计QTEventBus中的消息(其实是我没看)

使用

QTEventBus使用比较简单,主要是QTEventBus.h中的方法

  1. 添加监听
//监听全局总线,监听的生命周期和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 *)[_object_ subscribeNotification:_name_])
//全局总线监听QTJsonEvent
#define QTSubJSON(_object_,_name_) ((QTEventSubscriberMaker *)[_object_ subscribeSharedBusOfJSON:_name_])
  1. 发布消息
/**
 发布Event,等待event执行结束
 */
- (void)dispatch:(id)event;

/**
 异步到eventbus内部queue上dispath
 */
- (void)dispatchOnBusQueue:(id)event;

/**
 异步到主线程dispatch
 */
- (void)dispatchOnMain:(id)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 *(^)(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)next:(QTEventNextBlock)hander{
    return self.next(hander);
}

保存block回调和监听者,下面讲

保存监听者

既然创建好了监听者,第二步肯定就是保存了。QTEventBus是如何保存监听者的呢,我们看一下作者的示例

[QTSub(self, DemoEvent) next:^(DemoEvent *event) {
        NSLog(@"%ld",event.count);
}];

我们可以看到,紧着跟QTSub的是next。而保存监听者实际上就是在这一步中做的

- (id(^)(void(^)(id event)))next{
    return ^id(void(^hander)(__kindof NSObject * event)){
        self.hander = hander;
        return [self.eventBus _createNewSubscriber:self];
    };
}

先保存了block。然后调用了_createNewSubscriber

- (id)_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 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)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)event{
    dispatch_async(self.publishQueue, ^{
        [self dispatch:event];
    });
}

- (void)dispatchOnMain:(id)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 *(^)(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))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> *)tokens{
    if (!_tokens) {
        _tokens = [[NSMutableArray alloc] init];
    }
    return _tokens;
}

- (void)addToken:(id)token{
    @synchronized(self) {
        [self.tokens addObject:token];
    }
}

- (void)dealloc{
    @synchronized(self) {
        for (id 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中移除了该事件的监听

你可能感兴趣的:(QTEventBus)