- 小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
protocol匹配
protocol匹配的实现思路是:
-
将protocol和对应的类进行字典匹配
-
通过用protocol获取class,在动态创建实例
protocol比较典型的三方框架就是阿里的BeeHive。BeeHive借鉴了Spring Service、Apache DSO的架构理念,采用AOP+扩展App生命周期API形式,将业务功能、基础功能模块以模块方式以解决大型应用中的复杂问题,并让模块之间以Service形式调用,将复杂问题切分,以AOP方式模块化服务。
BeeHive 核心思想
-
各个模块间调用从直接调用对应模块,变成调用
Service的形式,避免了直接依赖。 -
App生命周期的分发,将耦合在
AppDelegate中逻辑拆分,每个模块以微应用的形式独立存在。
//******** 1、注册
[[BeeHive shareInstance] registerService:@protocol(HomeServiceProtocol) service:[BHViewController class]];
//******** 2、使用
#import "BHService.h"
id< HomeServiceProtocol > homeVc = [[BeeHive shareInstance] createService:@protocol(HomeServiceProtocol)];
优点
1、利用接口调用,实现了参数传递时的类型安全
2、直接使用模块的protocol接口,无需再重复封装
缺点
1、用框架来创建所有对象,创建方式不同,即不支持外部传入参数
2、用OC runtime创建对象,不支持swift
3、只做了protocol 和 class 的匹配,不支持更复杂的创建方式 和依赖注入
4、无法保证所使用的protocol 一定存在对应的模块,也无法直接判断某个protocol是否能用于获取模块
除了BeeHive,还有 Swinject
BeeHive 模块事件(Appdelegate 解耦)
BeeHive会给每个模块提供生命周期事件,用于与BeeHive宿主环境进行必要信息交互,感知模块生命周期的变化。
这里BHAppDelegate会继承自UIApplicationDelegate。
BHAppDelegate重写appdelegate的方法,在每个appdeleagte的不同状态下调用triggerEvent发送对应的消息给注册过的Module。
有以下这些枚举。
看到这里
BHMInitEvent和BHMTearDownEvent是比较特殊的事件需要调用相对应的方法之外,其他的会根据这些枚举来找到相对应的sel来发送消息给已经注册过的Module。这些Module需要遵循BHModuleProtoco的,否则无法接收到这些事件的消息。
流程图:
BeeHive 模块注册
在BeeHive主要是通过BHModuleManager来管理各个模块的。BHModuleManager中只会管理已经被注册过的模块。
BeeHive提供了三种不同的调用形式,静态plist,动态注册,annotation。Module、Service之间没有关联,每个业务模块可以单独实现Module或者Service的功能。
- 读取本地Plist文件
通过读取本地
Plist文件进行模块注册的话,最重要的就是要设置正确的Plist路径,一般是在Appdelegate里面的didFinishLaunchingWithOptions进行设置。
下面是需要配置的Dictionary的内容。
然后Beehive就会在loadLocalModules里面读取moduleClasses并且进行遍历加入到BHModuleInfos,等待之后进行注册操作。
- 动态注册
动态注册一般写在类的load方法里面,在load方法里面注册Module的类。这里的
registerDynamicModule最终会调用addModuleFromObject进行注册。
这里还可以使用BH_EXPORT_MODULE宏替代load方法进行注册。
- Annotation方式注册
这种方式主要是通过
BeeHiveMod宏进行Annotation标记。
//***** 使用
BeeHiveMod(ShopModule)
//***** BeeHiveMod的宏定义
#define BeeHiveMod(name) \
class BeeHive; char * k##name##_mod BeeHiveDATA(BeehiveMods) = ""#name"";
//***** BeeHiveDATA的宏定义
#define BeeHiveDATA(sectname) __attribute((used, section("__DATA,"#sectname" ")))
//***** 全部转换出来后为下面的格式
char * kShopModule_mod __attribute((used, section("__DATA,""BeehiveMods"" "))) = """ShopModule""";
BeeHive模块调用 在BeeHive中是通过BHServiceManager来管理各个Protocol的。BHServiceManager中只会管理已经被注册过的Protocol。
注册Protocol的方式总共有三种,和注册Module是一样一一对应的
读取本地Plist文件
- 首先同Module一样,需要先设置好路径。
- Plist配置好对应的protocol和controller。
- 然后
Beehive就会在registerLocalServices里面遍历读取plist文件中的字典,将service和impl匹配后加入到allServicesDict里面。
Plist里面的Module和service的注册都在setContext方法里,而setContext会在didFinishLaunchingWithOptions里面调用.
- 动态注册
service动态注册一般在modSetUp方法里面注册。这里的registerService最终会调用registerService将protocol和对应的controller添加到allServicesDict里面。
- Annotation方式注册
//****** 1、通过BeeHiveService宏进行Annotation标记
BeeHiveService(HomeServiceProtocol,BHViewController)
//****** 2、宏定义
#define BeeHiveService(servicename,impl) \
class BeeHive; char * k##servicename##_service BeeHiveDATA(BeehiveServices) = "{ \""#servicename"\" : \""#impl"\"}";
//****** 3、转换后的格式,也是将其存储到特殊的段
char * kHomeServiceProtocol_service __attribute((used, section("__DATA,""BeehiveServices"" "))) = "{ \"""HomeServiceProtocol""\" : \"""BHViewController""\"}";
调用的话直接用createService。createService会先检查Protocol协议是否注册过,然后接着取出字典里面对应的Class,如果实现了shareInstance方法,那么就创建一个单例对象,如果没有,那么就创建一个实例对象。如果还实现了singleton,就能进一步的把implInstance和serviceStr对应的加到BHContext的servicesByName字典里面缓存起来。这样就可以随着上下文传递了
- (id)createService:(Protocol *)proto;
{
return [[BHServiceManager sharedManager] createService:proto];
}
👇
- (id)createService:(Protocol *)service
{
return [self createService:service withServiceName:nil];
}
👇
- (id)createService:(Protocol *)service withServiceName:(NSString *)serviceName {
return [self createService:service withServiceName:serviceName shouldCache:YES];
}
👇
- (id)createService:(Protocol *)service withServiceName:(NSString *)serviceName shouldCache:(BOOL)shouldCache {
if (!serviceName.length) {
serviceName = NSStringFromProtocol(service);
}
id implInstance = nil;
//判断protocol是否已经注册过
if (![self checkValidService:service]) {
if (self.enableException) {
@throw [NSException exceptionWithName:NSInternalInconsistencyException reason:[NSString stringWithFormat:@"%@ protocol does not been registed", NSStringFromProtocol(service)] userInfo:nil];
}
}
NSString *serviceStr = serviceName;
//如果有缓存,则直接从缓存中获取
if (shouldCache) {
id protocolImpl = [[BHContext shareInstance] getServiceInstanceFromServiceName:serviceStr];
if (protocolImpl) {
return protocolImpl;
}
}
//获取类后,然后响应下层的方法
Class implClass = [self serviceImplClass:service];
if ([[implClass class] respondsToSelector:@selector(singleton)]) {
if ([[implClass class] singleton]) {
if ([[implClass class] respondsToSelector:@selector(shareInstance)])
//创建单例对象
implInstance = [[implClass class] shareInstance];
else
//创建实例对象
implInstance = [[implClass alloc] init];
if (shouldCache) {
//缓存
[[BHContext shareInstance] addServiceWithImplInstance:implInstance serviceName:serviceStr];
return implInstance;
} else {
return implInstance;
}
}
}
return [[implClass alloc] init];
}