美文网首页iOS-Developer-OC
QTEventBus架构分析

QTEventBus架构分析

作者: sankun | 来源:发表于2019-06-20 16:42 被阅读0次
    飞线图

    简介

    QTEventBus 事件总线集中管理事件流,跟ReactiveCocoa函数响应式编程框架类似(Functional reactive programming,简称FRP)能很好的,省略胶水代码.

    Event(事件)

    支持事件类型有NSString NSObject Notificaton QTJsonEvent QTAppEvent(应用生命周期事件) 等同于RAC里的signal

    Subscribe(订阅)

    订阅先于事件发布

    dispatch(发布)

    事件源出发布需要传递的事件

    使用前先订阅事件

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

    宏展开后

    // self 事件订阅者 _className_  泛型指定了 next 回调参数类型 subscribeSharedBus 是通过NSObject扩展里实现
    #define QTSub(_object_,_className_) ((QTEventSubscriberMaker<_className_ *> *)[_object_ subscribeSharedBus:[_className_ class]])
    
    

    subscribeSharedBus 在NSObject分类里实现

    // 此处是对 QTEventSubscriberMaker 做事件存储以及封装释放的处理 
    - (QTEventSubscriberMaker *)subscribeSharedBus:(Class)eventClass{
        return [QTEventBus shared].on(eventClass).freeWith(self);
    }
    
    // on是 QTEventSubscriberMaker对象的block属性 用来
    - (QTEventSubscriberMaker<id> *(^)(Class eventClass))on{
        return ^QTEventSubscriberMaker *(Class eventClass){
            return [[QTEventSubscriberMaker alloc] initWithEventBus:self
                                                         eventClass:eventClass];
        };
    }
    // QTEventSubscriberMaker 对象 
    @interface QTEventSubscriberMaker()
    
    - (instancetype)initWithEventBus:(QTEventBus *)eventBus
                          eventClass:(Class)eventClass;
    
    @property (strong, nonatomic) Class eventClass; // 事件类型
    
    @property (strong, nonatomic) NSObject * lifeTimeTracker; // QTEventSubscriberMaker释放的时候用
    
    @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
    
    
    // next:^(DemoEvent *event) {  将创建监听者 并保存至QTEventBusCollection中(内部实现是双向链表)
    
     [QTSub(self, DemoEvent) next:^(DemoEvent *event) {
            NSLog(@"%ld",event.count);
     }];
    
    - (id<QTEventToken>)next:(QTEventNextBlock)hander{
        return self.next(hander);
    }
    
    - (id<QTEventToken>(^)(void(^)(id event)))next{
        return ^id<QTEventToken>(void(^hander)(__kindof NSObject * event)){
            self.hander = hander;
            return [self.eventBus _createNewSubscriber:self];
        };
    }
    
    - (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;
    }
    
    - (_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];
            }
        };
    

    使用runtime 关联QTDisposeBag 管理监听对象 触发时机在监听者如VC dealloc后会释放关联对象

        //创建监听者
        _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;
    }
    

    以上是订阅事件做的工作.接下来看事件发布的处理

    - (IBAction)dispatchEvent:(id)sender {
        static long _count = 1;
        DemoEvent * event = [[DemoEvent alloc] init];
        event.count = _count;
        _count ++;
        [[QTEventBus shared] dispatch:event];
    }
    
    - (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];
    }
    

    根据 key 到collection 取出订阅者 并执行handle任务

    - (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);
                }
            }
    
        }
    }
    

    到此结束

    总结

    1, 订阅者存储使用字典加链表的方式
    2,DSL链式编程
    3,泛型的应用
    4,释放池的关联
    https://github.com/LeoMobileDeveloper/QTEventBus

    相关文章

      网友评论

        本文标题:QTEventBus架构分析

        本文链接:https://www.haomeiwen.com/subject/jiacxctx.html