使用Beehive框架原理对ios AppDelegate.m解

2020-08-28  本文已影响0人  小熊兜里有糖

起因

在iOS的项目中,有很多对接SDK或者其他方面的需求,需要在ios项目中的AppDelegate.m的生命周期方法中进行很多类似于初始化一样的操作,但是如果你直接把所有的相关代码直接写在这些生命周期函数中是一件耦合性非常强的工作,后续维护将变得十分难以处理,这一点有过相关开发经验的应该都了解,在我做的第一个也是唯一一个完整项目的时候,就曾经遇到过这样的问题,但是当时没有经验参考,而且项目比较小,没有太过于庞大的代码需要在这一部分处理,所以当时把这个问题遗留下来了,但是对于大的项目来说就是一个不得不面对的问题,所以现在有了前辈写的比较好的方式,所以一定要学习一下。项目中对于appdelegate是使用了阿里的一个框架Beehive的方式进行解耦,虽然仅仅只是对于AppDelegate.m生命周期函数处理这一个模块进行了解耦,但是其解耦原理可以进行总结和学习。

在具体方式总结之前先进行一下概念补充- ARM映像

areas

用于构建objects和映像(images)的代码和数据项。一个area包含代码或初始化的数据,或描述未初始化的或必须先设置为零才能执行映像的内存片段。区域的属性描述了该区域是只读,可读写,可执行,已初始化,零初始化还是未初始化。区域进一步分为更大的构建块,称为sections和regions,用于构建镜像。

Sections

地址空间中连续并具有相同属性的areas序列。一个section与其组成区域的其他sections具有相同的属性。一个section包含只读,可执行区域的部分是只读,可执行section。

regions

这些是地址空间中连续的sections序列。组成部分不必具有相同的属性。一个区域可以包括一个由一个零初始化section跟随的可读写section。

objects

包含一个或多个areas

Images

包含一个或多个regions

一个简单的image

attribute((section("name")))

section功能属性可以放置代码在image的不同sections中
在这个例子中Function_Attributes_section_0被放置在RO section中而不是.text文件中

void Function_Attributes_section_0 (void) 
    __attribute__ ((section ("new_section")));
void Function_Attributes_section_0 (void)
{
    static int aStatic =0;
    aStatic++;
}

attribute((used))

此函数属性通知编译器,即使未引用静态函数也要保留在目标文件中。

这一部分细节以及下文中使用到的关于section存取可以参考该

文章

实战:对于Appdelegate中生命周期函数调用的解耦

流程图

首先是准备性工作

类的存放

类的提取

以下代码的作用就是把之前写入section的类取出来放到数组中,方便后续处理,实际上最后是加入到了EventBus的eventDelegates数组中

//AppdelegatePluginManager.m 
NSArray<NSString *> *AppPluginReadConfiguration(char *sectionName, const struct mach_header *mhp);
static void dyld_callback(const struct mach_header *mhp, intptr_t vmaddr_slide) {
    NSArray *mods = AppPluginReadConfiguration(AppPluginSectName, mhp);
    for (NSString *modName in mods) {
        Class cls;
        if (modName) {
            cls = NSClassFromString(modName);
            if (cls) {
                [[QINAppdelegatePluginManager shareInstance] addPlugin:cls];
            }
        }
    }
}
//下面这个指令的作用是在main方法进入之前默认执行
__attribute__((constructor)) void registerDyldCallback() {
    _dyld_register_func_for_add_image(dyld_callback);
}

//从section中取出类名
NSArray<NSString *> *AppPluginReadConfiguration(char *sectionName, const struct mach_header *mhp) {
    NSMutableArray *configs = [NSMutableArray array];
    unsigned long size = 0;
#ifndef __LP64__
    uintptr_t *memory = (uintptr_t *)getsectiondata(mhp, SEG_DATA, sectionName, &size);
#else
    const struct mach_header_64 *mhp64 = (const struct mach_header_64 *)mhp;
    uintptr_t *memory = (uintptr_t *)getsectiondata(mhp64, SEG_DATA, sectionName, &size);
#endif

    unsigned long counter = size / sizeof(void *);
    for (int idx = 0; idx < counter; ++idx) {
        char *string = (char *)memory[idx];
        NSString *str = [NSString stringWithUTF8String:string];
        if (!str)
            continue;

        if (str)
            [configs addObject:str];
    }

    return configs;
}
//注意是写在@interface之前的
@interface AppdelegatePluginManager ()
。。。。。。

对于上文中的[[QINAppdelegatePluginManager shareInstance] addPlugin:cls];间接触发了下面的方法

//EventBus.m
- (void)addDelegate:(NSObject<QNBEventDelegate> *)delegate{
    [self.eventDelegates addObject:delegate];
}

生命周期函数触发流程

   //EventBus.m
   //数组声明
//用于存放所有注册了事件的类,不管是需要什么事件
@property (nonatomic,strong) NSMutableArray<NSObject<QNBEventDelegate> *> *_Nullable eventDelegates;
//字典,起到缓存作用,key为生命周期事件名,value为实现了事件的类的集合数组
@property (nonatomic,strong) NSMutableDictionary<NSString *,NSArray<QNBPluginEventNode *> *> *eventNodeDic;
   //初始化,也就是首次使用为空
- (instancetype)init
{
    self = [super init];
    if (self) {
        ......
        _eventDelegates = [[NSMutableArray alloc] init];
        _eventNodeDic = [[NSMutableDictionary alloc] init];
        .....
    }
    return self;
}
   //eventDelegates数组数据获取入口,在上文的main函数enter之前被默认调用的函数的中被间接调用,该数组使用见下文
- (void)addDelegate:(NSObject<QNBEventDelegate> *)delegate{
    [self.eventDelegates addObject:delegate];
 }
    
//EventBus.m
-(BOOL)resumeEvent:(nonnull QNBEvent *)event withDelegate:(nullable NSObject<QNBEventDelegate> *)delegate{
   
    if(!event){
        return NO;
    }
    
    @try {
        NSString *eventName = event.eventName;
        NSArray<QNBPluginEventNode *> *eventNodes = [_eventNodeDic objectForKey:eventName];
        BOOL isPassedDelegate = delegate ? NO : YES;
        BOOL isBlocked = NO;
        
        //走cache逻辑
        if(eventNodes){
            for(QNBPluginEventNode *node in eventNodes){
                
                //跳过在delegate之前的监听者
                if(!isPassedDelegate && node.pluginObj == delegate){
                    isPassedDelegate = YES;
                    continue;
                }
                
                if([_blockedDelegates containsObject:node.pluginObj]){
                    continue;
                }
                
                if(!isPassedDelegate){
                    continue;
                }
                
                void (*commonReceiveIMP) (id,SEL,id) = (void (*)(id,SEL,id))node.commonReceiveIMP;
                if(commonReceiveIMP){
                    commonReceiveIMP(node.pluginObj,_commonReceiveSEL,event);
                    //QNBLogInfo(@"[QNBEventTest] Cache %@:%@",[NSString stringWithFormat:@"didRecievePlayerEvent:"],[node.pluginObj class]);
                }
                
                BOOL (*specialEventIMP) (id,SEL,id) = (BOOL (*)(id,SEL,id))node.specialReceiveIMP;
                if(specialEventIMP){
                    isBlocked = specialEventIMP(node.pluginObj,node.specialReceiveSEL,event);
                    //QNBLogInfo(@"[QNBEventTest] Cache %@:%@",[NSString stringWithFormat:@"didReceive%@:",eventName],[node.pluginObj class]);
                }
                
                if(node.brigeObj){
                    BOOL (*bridgeReceiveIMP) (id,SEL,id) = (BOOL (*)(id,SEL,id))node.bridgeReceiveIMP;
                    if(bridgeReceiveIMP){
                        isBlocked = bridgeReceiveIMP(node.brigeObj,node.specialReceiveSEL,event);
                        //QNBLogInfo(@"[QNBEventTest] brige Cache %@:%@",[NSString stringWithFormat:@"didReceive%@:",eventName],[node.pluginObj class]);
                    }
                }
                
                if(isBlocked){
                    return YES;
                }

            }
        }

不走cache逻辑的部分

else{
            
            
            NSMutableArray<QNBPluginEventNode *> *eventNodes = [[NSMutableArray alloc] init];
            SEL specialEventSEL = NSSelectorFromString([NSString stringWithFormat:@"didReceive%@:",eventName]);
            
            for(NSObject<QNBEventDelegate> *eventDelegate in _eventDelegates){
                
                QNBPluginEventNode *eventNode = nil;
                
                if([eventDelegate respondsToSelector:_commonReceiveSEL]){
                    void (*commonEventIMP) (id,SEL,id) = (void (*)(id,SEL,id))[eventDelegate methodForSelector:_commonReceiveSEL];
                    if(commonEventIMP){
                        if(![_blockedDelegates containsObject:eventDelegate] && isPassedDelegate && !isBlocked){
                            commonEventIMP(eventDelegate,_commonReceiveSEL,event);
                            //QNBLogInfo(@"[QNBEventTest] %@:%@",[NSString stringWithFormat:@"didRecievePlayerEvent:"],[eventDelegate class]);
                        }
                        
                        eventNode = [[QNBPluginEventNode alloc] init];
                        eventNode.pluginObj = eventDelegate;
                        eventNode.commonReceiveIMP = (IMP)commonEventIMP;
                        [eventNodes addObject:eventNode];
                    }

                }
                
                if([eventDelegate respondsToSelector:specialEventSEL]){
                    BOOL (*specialEventIMP) (id,SEL,id) = (BOOL (*)(id,SEL,id))[eventDelegate methodForSelector:specialEventSEL];
                    if(specialEventIMP){
                        if(![_blockedDelegates containsObject:eventDelegate] && isPassedDelegate && !isBlocked){
                            isBlocked = specialEventIMP(eventDelegate,specialEventSEL,event);
                        }
                        //QNBLogInfo(@"[QNBEventTest] %@:%@",[NSString stringWithFormat:@"didInterceptPlayerEvent:"],[eventDelegate class]);
                        
                        if(!eventNode){
                            eventNode = [[QNBPluginEventNode alloc] init];
                            eventNode.pluginObj = eventDelegate;
                            [eventNodes addObject:eventNode];
                        }
                        eventNode.specialReceiveSEL = specialEventSEL;
                        eventNode.specialReceiveIMP = (IMP)specialEventIMP;
                    }
                    
                    
                }
                
                if([eventDelegate isKindOfClass:[QNBPluginViewControllerBridge class]]){
                    QNBPluginViewControllerBridge *eventBridge = (QNBPluginViewControllerBridge *)eventDelegate;
                    if(eventBridge.eventTargetViewController){
                        if([eventBridge.eventTargetViewController respondsToSelector:specialEventSEL]){
                            BOOL (*brigdeEventIMP) (id,SEL,id) = (BOOL (*)(id,SEL,id))[eventBridge.eventTargetViewController methodForSelector:specialEventSEL];
                            if(brigdeEventIMP){
                                if(![_blockedDelegates containsObject:eventDelegate] && isPassedDelegate && !isBlocked){
                                    isBlocked = brigdeEventIMP(eventBridge.eventTargetViewController,specialEventSEL,event);
                                }
                                if(!eventNode){
                                    eventNode = [[QNBPluginEventNode alloc] init];
                                    eventNode.pluginObj = eventDelegate;
                                    [eventNodes addObject:eventNode];
                                }
                                
                                eventNode.brigeObj = eventBridge.eventTargetViewController;
                                eventNode.specialReceiveSEL = specialEventSEL;
                                eventNode.bridgeReceiveIMP = (IMP)brigdeEventIMP;
                                
                                //QNBLogInfo(@"[QNBEventTest] brige %@:%@",[NSString stringWithFormat:@"didReceive%@:",eventName],eventBridge.eventTargetViewController);
                            }
                            
                        }
                    }
                }
                
                //跳过在delegate之前的监听者
                if(!isPassedDelegate && eventDelegate == delegate){
                    isPassedDelegate = YES;
                }
                
                
            }
            
            [_eventNodeDic setObject:eventNodes forKey:eventName];
            
            if(isBlocked){
                return YES;
            }
            
        }
                

上一篇 下一篇

猜你喜欢

热点阅读