原理 : QTEventBus 将事件根据 key 保存到一个 array 中, 在发送事件时候, 查找map 中 key 对应的 array, 然后遍历 array调用事件
- 使用 block 实现链式编程, 这个在项目中用的很少, 需要熟练使用才可([QTEventBus shared]返回的是个QTEventBus 类型的对象, 然后调用[QTEventBus shared].on(NSObject) 返回一个 QTEventSubscriberMaker 类型的对象, 之后就开始了链式编程的路)
@interface QTEventBus<EventType> : NSObject
@property (class,readonly) QTEventBus * shared;
- (QTEventSubscriberMaker<EventType> *)on:(Class)eventClass;
@end
- 在 QTEventSubscriberMaker 中使用泛型, 这样调用 next()时候, 会直接把传入的类返回回来
// - 如果不使用泛型
[QTSub(self, DemoEvent) next:^(id event) {
<#code#>
}];
// - 使用泛型
[QTSub(self, DemoEvent) next:^(DemoEvent *event) {
<#code#>
}];
// - 原因 :
#define QTSub(_object_,_className_) ((QTEventSubscriberMaker <_className_ *> *)[_object_ subscribeSharedBus:[_className_ class]])
// - 1. 声明对象时候用到了 泛型
QTEventSubscriberMaker <_className_ *> *)
// - 2. 定义的 block 的参数使用了泛型的声明
typedef void (^QTEventNextBlock)(Value event) NS_SWIFT_UNAVAILABLE("");
// - 3. next 的参数是使用泛型的 block
- (id<QTEventToken>)next:(QTEventNextBlock)hander{
return self.next(hander);
}
- 自动释放的原理(让A对象释放的时候, 释放掉bag, 即动态给A 对象添加一个eb_disposeBag属性, 当 A dealloc 时候, 会触发QTDisposeBag的 dealloc, 当 QTDisposeBag dealloc 时候, 会调用加入到 QTDisposeBag中的 tokens 中的所有对象, 然后调用每个对象的 dispose 方法)
@implementation NSObject (QTEventBus_Private)
- (QTDisposeBag *)eb_disposeBag{
QTDisposeBag * bag = objc_getAssociatedObject(self, &event_bus_disposeContext);
if (!bag) {
bag = [[QTDisposeBag alloc] init];
objc_setAssociatedObject(self, &event_bus_disposeContext, bag, OBJC_ASSOCIATION_RETAIN);
}
return bag;
}
@implementation QTDisposeBag
- (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];
}
}
}
}
- 这里的很多对象都是随时添加, 删除,替换的, 如果使用数组, 效率比较低, 这里使用的链表, 在 OC 中的链表的设计
@interface QTEventBusCollection : NSObject
// - linkListTable 中有很多链表
@property (strong, nonatomic) NSMutableDictionary<NSString *,_QTEventBusLinkList *> * linkListTable;
@interface _QTEventBusLinkList: NSObject
// - 头结点
@property (strong, nonatomic) _QTEventBusLinkNode * head;
// - 尾节点
@property (strong, nonatomic) _QTEventBusLinkNode * tail;
// - 存储节点和 key 对应的键值对, 方便快速查找 节点
@property (strong, nonatomic) NSMutableDictionary * registeredNodeTable;
@interface _QTEventBusLinkNode: NSObject
// - 上一个节点
@property (weak, nonatomic) _QTEventBusLinkNode * previous;
// - 下一个节点
@property (weak, nonatomic) _QTEventBusLinkNode * next;
// - 删除的操作 : 需要通过 key 从 registeredNodeTable 中找到 node, 然后才可以链表中的某个 node 做删除的操作.
// - 插入的操作 : 需要通过 key 从 registeredNodeTable 中找到 某个相邻的node, 然后修改相邻节点和本 node的上一节点或下一节点, 实现插入操作
- 使用类别和宏定义
// - 1. 使用类别使每个对象都能轻易调到这个方法
[QTEventBus shared].on(xx) ----- 优化为 ----> [self subscribeSharedBus:xx]
// - 2. 使用宏定义
[(QTEventSubscriberMaker <DemoEvent *>*)[self subscribeSharedBus:[NSObject class]] next:^(DemoEvent *event) {
NSLog(@"%ld",event.count);
}];
------------ 优化为 ---------->
[QTSub(self, DemoEvent) next:^(DemoEvent *event) {
NSLog(@"%ld",event.count);
}];
- 使用内联函数, 常用的且简单重复的代码封装在使用内联函数中
- 巧用协议
// - _QTEventToken 和 _QTComposeToken 都遵守了 QTEventToken 协议, 而 QTEventToken 只有一个 - (void)dispose; 函数, 就是当 QTDisposeBag 释放时候, 调用每个 token 的释放, 而 _QTComposeToken 内部有个 NSArray<_QTEventToken *> * tokens; 当 _QTComposeToken dispose 时候, 就是遍历数组,调用每个元素的 dispose, 而每个 token 的 dispose 就是调用 token 的 @property (copy, nonatomic) void(^onDispose)(NSString * uniqueId); block
- (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;
}