这是一个模块化的框架,引入了中间层BeeHive来注册和持有各个模块和服务,模块间的调用通过protocol来解耦,但是同时每个模块都需要依赖protocol。每个模块中的moduleClass和services并没有很强的依赖,moduleClass负责一些系统,通用事件的回调,service负责业务和逻辑的实现。
1.BeeHive的框架结构
这个架构图可以这样理解:
1.Context是一个上下文,保存一些系统配置,需要注册的module和service列表,app的编译环境等等。它可以和BHCore以及模块交互。
2.BHCore是BeeHive的核心代码,负责module和service的注册,模块之间的互调(其实也就是模块里service的调度)。
3.module包括一个moduleClass和多个serviceClass。
简化一下就变成下图,更易于理解:
2.BeeHive需要了解的几个要点
1.模块指的是什么?
这里的模块是一个整体概念,其中包括一个moduleClass和多个service。
2.模块注册和服务注册是什么意思?
模块注册可以理解为为整个模块注册了一个可以接受事件(系统事件,通用事件以及业务自定义事件)的类,其实就是moduleClass的实例化。
3.事件指的是什么?如何定义业务事件?事件在哪里注册?
事件包括系统事件,通用事件和业务自定义事件。系统事件,指的是Application的生命周期事件,比如:EnterBackground,EnterForeground。通用事件,是BeeHive自己定义的模块生命事件,比如:moduleSetup,moduleInit。业务自定义事件,需要用户自己扩展,继承BHAppdelegate实现相应事件的注册。BeeHive自己定义了一个BHAppdelegate,入口Appdelegate需要继承BHAppdelegate,所有的事件也是在Appdelegate里定义和调用。
4.moduleClass和service之间的关系?
moduleClass和service其实是一个模块之间的不同组成部分,它们之间并没有很强的逻辑关系,moduleClass负责接收各种事件以及事件的处理,而service负责业务的功能实现。比如说,可以在moduleClass生命周期函数注册service。模块之间的通讯需要通过service暴露出来的协议接口来实现。
5.BeeHive怎么模块解耦?
这个问题主要是框架设计的问题,首先业务代码之间不互相直接依赖,通过BeeHive来获取相应的实例,然后通过全局protocol暴露出来的接口进行函数调度。说白了,就是通过协议解耦,但同时所有的service都会依赖这个protocol,类似于隔了一层中间层。
6.模块注册方式?
(1)静态注册
也就是本地加载,通过bundle加载模块生成数据,如下图:
(2)动态注册
#define BH_EXPORT_MODULE(isAsync) \
+ (void)load { [BeeHive registerDynamicModule:[self class]]; } \
-(BOOL)async { return [[NSString stringWithUTF8String:#isAsync] boolValue];}
@interface MessageModule ()<BHModuleProtocol>
@end
@implementation MessageModule
BH_EXPORT_MODULE();
@end
调用BH_EXPORT_MODULE()宏,在load函数调用registerDynamicModule:注册改模块。改宏可以穿入一个异步参数,默认为NO,如果为YES则会在启动之后第一屏内容展现之前异步执行模块的初始化,可以优化启动时时间消耗。
(3)Annotation注册
@BeeHiveMod(MainModule) //注册MainModule
@interface MainModule ()<BHModuleProtocol>
@end
//注册方法实现
#ifndef BeehiveModSectName
#define BeehiveModSectName "BeehiveMods"
#endif
#define BeeHiveDATA(sectname) __attribute((used, section("__DATA,"#sectname" ")))
#define BeeHiveMod(name) \
class BeeHive; char * k##name##_mod BeeHiveDATA(BeehiveMods) = ""#name"";
代码段注册,也就是直接操作代码段。感兴趣的同学可以导出app编译的源文件,可以在_data段看到BeehiveMods。具体怎么看app编译后的可执行文件,请移步《iOS APP可执行文件的组成》。
7.服务的注册方式?
(1)静态注册
(2)API调用
- (void)modSetUp:(BHContext *)context {
[[BHServiceManager sharedManager] registerService: @protocol(PersonServiceProtocol) implClass: [PersonModuleService class]];
}
(3)Annotation注册
@BeeHiveService(MainServiceProtocol, MainModuleService)
@interface MainModuleService ()<MainServiceProtocol>
@end
#ifndef BeehiveServiceSectName
#define BeehiveServiceSectName "BeehiveServices"
#endif
#define BeeHiveDATA(sectname) __attribute((used, section("__DATA,"#sectname" ")))
#define BeeHiveService(servicename,impl) \
class BeeHive;char * k##servicename##_service BeeHiveDATA(BeehiveServices) = "{ \""#servicename"\" : \""#impl"\"}";
3.BeeHive的项目使用
1.先引入BeeHive库,可以直接复制,也可以使用pod来管理。
2.把系统生成的Appdelegate干掉,新建一个继承BHAppdelegate的子类,把它改成入口类。
3.配置BHContext,如下图:
[BHContext shareInstance].application = application;
[BHContext shareInstance].launchOptions = launchOptions;
[BHContext shareInstance].env = BHEnvironmentDev;
[BHContext shareInstance].moduleConfigName = @"BeeHive.bundle/BeeHive-Jashion";
[BHContext shareInstance].serviceConfigName = @"BeeHive.bundle/BHService-Jashion";
moduleConfigName设置本地模块加载地址,serviceConfigName设置本地服务加载地址。
4.加载配置,初始化BeeHive
[BeeHive shareInstance].enableException = YES;
[[BeeHive shareInstance] setContext: [BHContext shareInstance]];
5.设置rootController
id<MainServiceProtocol> mainVC = [[BeeHive shareInstance] createService: @protocol(MainServiceProtocol)];
if ([mainVC isKindOfClass: [UIViewController class]]) {
UINavigationController *navCtrl = [[UINavigationController alloc] initWithRootViewController: (UIViewController *)mainVC];
self.window = [[UIWindow alloc] initWithFrame: [UIScreen mainScreen].bounds];
self.window.rootViewController = navCtrl;
[self.window makeKeyAndVisible];
}
6.模块之间的调用
id<MainServiceProtocol> mainVC = [[BeeHive shareInstance] createService: @protocol(MainServiceProtocol)];
通过BeeHive获取相应的实例,然后通过protocol调用service暴露出来的方法。
总结:##
我觉得整个架构不是很清晰,也有可能初步接触,还不太深入了解。解耦,我只看到了service之间的调用解耦,但是都依赖了协议。这个比运用runtime的反射机制来解耦函数间的调用的好处在于,可以在编译期间发现错误,而非运行时。而且,只要注册了的module和service的实例就会一直被BeeHive持有,这可能会造成资源的浪费。继续观望中。