本文主要介紹組件化通訊的三種方式
URL路由 ---- MGJRouter
基于URL匹配或者命名約定击胜,通過runtime動(dòng)態(tài)調(diào)用捌浩,實(shí)現(xiàn)簡單快集,類似系統(tǒng)的openURL
優(yōu)點(diǎn)
- 極高的動(dòng)態(tài)性
- 可以統(tǒng)一管理多平臺的路由規(guī)則
- 可以適配 URL Scheme
缺點(diǎn)
- 參數(shù)通過字符串形式轉(zhuǎn)換,方式有限葵袭,編譯期無法進(jìn)行類型檢測
- 參數(shù)格式不明確
- 不支持Storyboard
- 無法保證使用模塊一定存在
- 解耦能力有限涵妥,url字符串一旦修改會導(dǎo)致其他地方失效
MGJRouter
- App啟動(dòng)時(shí)實(shí)例化所需的組件模塊,注冊
url
- 需要調(diào)用其他模塊時(shí)坡锡,傳遞
url
和參數(shù)蓬网,類似系統(tǒng)的openURL
//注冊url
[MGJRouter registerURLPattern:@"mgj://category/travel" toHandler:^(NSDictionary *routerParameters) {
NSLog(@"routerParameters == %@",routerParameters);
}];
//調(diào)用路由
[MGJRouter openURL:@"mgj://category/travel" withUserInfo:@{@"user_id": @1900} completion:nil];
Target-Action -- CTMediator
基于runtime和category特性,動(dòng)態(tài)獲取模塊鹉勒,例如通過NSClassFromString
獲取實(shí)例帆锋,performSelector + NSInvocation
動(dòng)態(tài)調(diào)用方法
- 利用分類添加路由接口,通過字符串獲取對應(yīng)的類
- 通過runtime創(chuàng)建實(shí)例禽额,動(dòng)態(tài)調(diào)用方法
優(yōu)點(diǎn)
- 通過
category
明確接口聲明 輕量
缺點(diǎn)
- 模塊化繁瑣窟坐,需要在
target、mediator
重新添加每個(gè)接口 -
category
中通過字符串識別绵疲,存在和URL路由一樣的問題 - 無法保證使用的模塊一定存在,target修改后臣疑,運(yùn)行時(shí)才能報(bào)錯(cuò)
CTMediator
在分類中通過調(diào)用performTarget:action:params:shouldCacheTarget:
方法盔憨,找到對應(yīng)的target
和action
- (id)performTarget:(NSString *)targetName action:(NSString *)actionName params:(NSDictionary *)params shouldCacheTarget:(BOOL)shouldCacheTarget
{
if (targetName == nil || actionName == nil) {
return nil;
}
//在swift中使用時(shí),需要傳入對應(yīng)項(xiàng)目的target名稱讯沈,否則會找不到視圖控制器
NSString *swiftModuleName = params[kCTMediatorParamsKeySwiftTargetModuleName];
// generate target 生成target
NSString *targetClassString = nil;
if (swiftModuleName.length > 0) {
//swift中target文件名拼接
targetClassString = [NSString stringWithFormat:@"%@.Target_%@", swiftModuleName, targetName];
} else {
//OC中target文件名拼接
targetClassString = [NSString stringWithFormat:@"Target_%@", targetName];
}
//緩存中查找target
NSObject *target = [self safeFetchCachedTarget:targetClassString];
//緩存中沒有target
if (target == nil) {
//通過字符串獲取對應(yīng)的類
Class targetClass = NSClassFromString(targetClassString);
//創(chuàng)建實(shí)例
target = [[targetClass alloc] init];
}
// generate action 生成action方法名稱
NSString *actionString = [NSString stringWithFormat:@"Action_%@:", actionName];
//通過方法名字符串獲取對應(yīng)的sel
SEL action = NSSelectorFromString(actionString);
if (target == nil) {
// 這里是處理無響應(yīng)請求的地方之一郁岩,這個(gè)demo做得比較簡單,如果沒有可以響應(yīng)的target缺狠,就直接return了问慎。實(shí)際開發(fā)過程中是可以事先給一個(gè)固定的target專門用于在這個(gè)時(shí)候頂上,然后處理這種請求的
[self NoTargetActionResponseWithTargetString:targetClassString selectorString:actionString originParams:params];
return nil;
}
//是否需要緩存
if (shouldCacheTarget) {
[self safeSetCachedTarget:target key:targetClassString];
}
//是否響應(yīng)sel
if ([target respondsToSelector:action]) {
//動(dòng)態(tài)調(diào)用方法
return [self safePerformAction:action target:target params:params];
} else {
// 這里是處理無響應(yīng)請求的地方挤茄,如果無響應(yīng)如叼,則嘗試調(diào)用對應(yīng)target的notFound方法統(tǒng)一處理
SEL action = NSSelectorFromString(@"notFound:");
if ([target respondsToSelector:action]) {
return [self safePerformAction:action target:target params:params];
} else {
// 這里也是處理無響應(yīng)請求的地方,在notFound都沒有的時(shí)候穷劈,這個(gè)demo是直接return了笼恰。實(shí)際開發(fā)過程中踊沸,可以用前面提到的固定的target頂上的。
[self NoTargetActionResponseWithTargetString:targetClassString selectorString:actionString originParams:params];
@synchronized (self) {
[self.cachedTarget removeObjectForKey:targetClassString];
}
return nil;
}
}
}
-
safePerformAction:target:params:
方法的實(shí)現(xiàn)社证,是通過NSInvocation
進(jìn)行消息轉(zhuǎn)發(fā)+參數(shù)傳遞
- (id)safePerformAction:(SEL)action target:(NSObject *)target params:(NSDictionary *)params
{
//獲取方法簽名
NSMethodSignature* methodSig = [target methodSignatureForSelector:action];
if(methodSig == nil) {
return nil;
}
//判斷返回類型逼龟,根據(jù)返回值完成參數(shù)傳遞
const char* retType = [methodSig methodReturnType];
//void類型
if (strcmp(retType, @encode(void)) == 0) {
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
[invocation setArgument:¶ms atIndex:2];
[invocation setSelector:action];
[invocation setTarget:target];
[invocation invoke];
return nil;
}
//NSInteger類型
if (strcmp(retType, @encode(NSInteger)) == 0) {
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
[invocation setArgument:¶ms atIndex:2];
[invocation setSelector:action];
[invocation setTarget:target];
[invocation invoke];
NSInteger result = 0;
[invocation getReturnValue:&result];
return @(result);
}
//BOOL類型
if (strcmp(retType, @encode(BOOL)) == 0) {
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
[invocation setArgument:¶ms atIndex:2];
[invocation setSelector:action];
[invocation setTarget:target];
[invocation invoke];
BOOL result = 0;
[invocation getReturnValue:&result];
return @(result);
}
//CGFloat類型
if (strcmp(retType, @encode(CGFloat)) == 0) {
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
[invocation setArgument:¶ms atIndex:2];
[invocation setSelector:action];
[invocation setTarget:target];
[invocation invoke];
CGFloat result = 0;
[invocation getReturnValue:&result];
return @(result);
}
//NSUInteger類型
if (strcmp(retType, @encode(NSUInteger)) == 0) {
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
[invocation setArgument:¶ms atIndex:2];
[invocation setSelector:action];
[invocation setTarget:target];
[invocation invoke];
NSUInteger result = 0;
[invocation getReturnValue:&result];
return @(result);
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
return [target performSelector:action withObject:params];
#pragma clang diagnostic pop
}
Protocol Class -- BeeHive
- 將
protocol
和對應(yīng)的類
字典匹配 - 通過
protocol
獲取class
動(dòng)態(tài)創(chuàng)建
優(yōu)點(diǎn)
- 通過接口調(diào)用,保證參數(shù)類型安全
- 直接使用
protocol
接口追葡,無需重復(fù)封裝
缺點(diǎn)
- 不支持swift
- 無法保證使用的Protocol一定存在對應(yīng)模塊
- 通過框架創(chuàng)建所有對象腺律,不支持外部傳入?yún)?shù)
BeeHive
BeeHive
借鑒了Spring Service、Apache DSO的架構(gòu)理念宜肉,采用AOP+擴(kuò)展Application API
形式匀钧,將業(yè)務(wù)
和基礎(chǔ)功能
通過模塊方法解耦,模塊直接通過Service
形式調(diào)用崖飘,避免直接依賴榴捡,在AppDelegate
中解耦,進(jìn)行邏輯拆分朱浴,每個(gè)模塊微應(yīng)用形式獨(dú)立存在
BeeHive 注冊
BeeHive
通過BHModuleManager
來管理已經(jīng)被注冊的模塊
BeeHive
提供了三種注冊方法:.plist
吊圾、動(dòng)態(tài)注冊(load)
、Annotation
.plist文件
- 設(shè)置
plist文件路徑
[BHContext shareInstance].moduleConfigName = @"BeeHive.bundle/BeeHive";//可選翰蠢,默認(rèn)為BeeHive.bundle/BeeHive.plist
-
創(chuàng)建
plist文件
loadLocalModules
方法讀取plist
文件项乒,添加到BHModuleInfos
數(shù)組
#pragma mark - Private
//初始化context,加載Modules梁沧、Services
-(void)setContext:(BHContext *)context
{
_context = context;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self loadStaticServices];
[self loadStaticModules];
});
}
//加載modules
- (void)loadStaticModules
{
// 讀取本地plist文件里面的Module檀何,并注冊到BHModuleManager的BHModuleInfos數(shù)組中
[[BHModuleManager sharedManager] loadLocalModules];
//注冊所有modules,在內(nèi)部根據(jù)優(yōu)先級進(jìn)行排序
[[BHModuleManager sharedManager] registedAllModules];
}
- (void)loadLocalModules
{
//plist文件路徑
NSString *plistPath = [[NSBundle mainBundle] pathForResource:[BHContext shareInstance].moduleConfigName ofType:@"plist"];
//判斷文件是否存在
if (![[NSFileManager defaultManager] fileExistsAtPath:plistPath]) {
return;
}
//讀取整個(gè)文件[@"moduleClasses" : 數(shù)組]
NSDictionary *moduleList = [[NSDictionary alloc] initWithContentsOfFile:plistPath];
//通過moduleClasses key讀取 數(shù)組 [[@"moduleClass":"aaa", @"moduleLevel": @"bbb"], [...]]
NSArray<NSDictionary *> *modulesArray = [moduleList objectForKey:kModuleArrayKey];
NSMutableDictionary<NSString *, NSNumber *> *moduleInfoByClass = @{}.mutableCopy;
//遍歷數(shù)組
[self.BHModuleInfos enumerateObjectsUsingBlock:^(NSDictionary * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[moduleInfoByClass setObject:@1 forKey:[obj objectForKey:kModuleInfoNameKey]];
}];
[modulesArray enumerateObjectsUsingBlock:^(NSDictionary * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if (!moduleInfoByClass[[obj objectForKey:kModuleInfoNameKey]]) {
//存儲到 BHModuleInfos 中
[self.BHModuleInfos addObject:obj];
}
}];
}
動(dòng)態(tài)注冊(load)
- 在
load
方法中注冊
+ (void)load
{
[BeeHive registerDynamicModule:[self class]];
}
-
registerDynamicModule
方法
+ (void)registerDynamicModule:(Class)moduleClass
{
[[BHModuleManager sharedManager] registerDynamicModule:moduleClass];
}
- (void)registerDynamicModule:(Class)moduleClass
{
[self registerDynamicModule:moduleClass shouldTriggerInitEvent:NO];
}
- (void)registerDynamicModule:(Class)moduleClass
shouldTriggerInitEvent:(BOOL)shouldTriggerInitEvent
{
[self addModuleFromObject:moduleClass shouldTriggerInitEvent:shouldTriggerInitEvent];
}
- 或者通過宏定義
BH_EXPORT_MODULE
代替load
方法
#define BH_EXPORT_MODULE(isAsync) \
+ (void)load { [BeeHive registerDynamicModule:[self class]]; } \
-(BOOL)async { return [[NSString stringWithUTF8String:#isAsync] boolValue];}
Annotation注冊
- 通過
BeeHiveMod
的宏進(jìn)行Annotation
標(biāo)記
//***** 使用
BeeHiveMod(ShopModule)
//***** BeeHiveMod的宏定義
#define BeeHiveMod(name) \
class BeeHive; char * k##name##_mod BeeHiveDATA(BeehiveMods) = ""#name"";
//***** BeeHiveDATA的宏定義
#define BeeHiveDATA(sectname) __attribute((used, section("__DATA,"#sectname" ")))
//***** 全部轉(zhuǎn)換出來后為下面的格式
char * kShopModule_mod __attribute((used, section("__DATA,""BeehiveMods"" "))) = """ShopModule""";
__attribute
第一個(gè)參數(shù)
used
:用來修飾函數(shù)廷支,被修飾后频鉴,意味著即使函數(shù)沒有被引用,在Release下也不會被優(yōu)化section("__DATA,""BeehiveMods"" ")
:指定未被優(yōu)化的模塊注入Mach-o
的__DATA
段BHReadConfiguration
方法讀取Mach-o
中的數(shù)據(jù)段恋拍,取出存放到數(shù)組
NSArray<NSString *>* BHReadConfiguration(char *sectionName,const struct mach_header *mhp)
{
NSMutableArray *configs = [NSMutableArray array];
unsigned long size = 0;
#ifndef __LP64__
// 找到之前存儲的數(shù)據(jù)段(Module找BeehiveMods段 和 Service找BeehiveServices段)的一片內(nèi)存
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*);
// 把特殊段里面的數(shù)據(jù)都轉(zhuǎn)換成字符串存入數(shù)組中
for(int idx = 0; idx < counter; ++idx){
char *string = (char*)memory[idx];
NSString *str = [NSString stringWithUTF8String:string];
if(!str)continue;
BHLog(@"config = %@", str);
if(str) [configs addObject:str];
}
return configs;
}
BeeHive模塊事件
BeeHive給每個(gè)模塊提供Application
生命周期事件垛孔,用于與主程序進(jìn)行必要信息交互,感知模塊生命周期的變化施敢。
所有的Module
必須遵守BHModuleProtocol
協(xié)議周荐,否則無法接受事件消息
在BHModuleManager
中,所有時(shí)間被定義成枚舉BHModuleEventType
typedef NS_ENUM(NSInteger, BHModuleEventType)
{
//設(shè)置Module模塊
BHMSetupEvent = 0,
//用于初始化Module模塊僵娃,例如環(huán)境判斷概作,根據(jù)不同環(huán)境進(jìn)行不同初始化
BHMInitEvent,
//用于拆除Module模塊
BHMTearDownEvent,
BHMSplashEvent,
BHMQuickActionEvent,
BHMWillResignActiveEvent,
BHMDidEnterBackgroundEvent,
BHMWillEnterForegroundEvent,
BHMDidBecomeActiveEvent,
BHMWillTerminateEvent,
BHMUnmountEvent,
BHMOpenURLEvent,
BHMDidReceiveMemoryWarningEvent,
BHMDidFailToRegisterForRemoteNotificationsEvent,
BHMDidRegisterForRemoteNotificationsEvent,
BHMDidReceiveRemoteNotificationEvent,
BHMDidReceiveLocalNotificationEvent,
BHMWillPresentNotificationEvent,
BHMDidReceiveNotificationResponseEvent,
BHMWillContinueUserActivityEvent,
BHMContinueUserActivityEvent,
BHMDidFailToContinueUserActivityEvent,
BHMDidUpdateUserActivityEvent,
BHMHandleWatchKitExtensionRequestEvent,
BHMDidCustomEvent = 1000
};
-
系統(tǒng)事件
:Application生命周期
通過將項(xiàng)目的AppDelegate
繼承BHAppDelegate
@interface TestAppDelegate : BHAppDelegate <UIApplicationDelegate>
-
應(yīng)用事件
:官方給出的流程圖,其中modSetup默怨、modInit等讯榕,可以用于編碼實(shí)現(xiàn)各插件模塊的設(shè)置與初始化。
自定義事件
:可以通過調(diào)用BHModuleManager
的triggerEvent :
方法處理所有事件
- (void)triggerEvent:(NSInteger)eventType
{
[self triggerEvent:eventType withCustomParam:nil];
}
- (void)triggerEvent:(NSInteger)eventType
withCustomParam:(NSDictionary *)customParam {
[self handleModuleEvent:eventType forTarget:nil withCustomParam:customParam];
}
#pragma mark - module protocol
- (void)handleModuleEvent:(NSInteger)eventType
forTarget:(id<BHModuleProtocol>)target
withCustomParam:(NSDictionary *)customParam
{
switch (eventType) {
//初始化事件
case BHMInitEvent:
//special
[self handleModulesInitEventForTarget:nil withCustomParam :customParam];
break;
//析構(gòu)事件
case BHMTearDownEvent:
//special
[self handleModulesTearDownEventForTarget:nil withCustomParam:customParam];
break;
//其他3類事件
default: {
NSString *selectorStr = [self.BHSelectorByEvent objectForKey:@(eventType)];
[self handleModuleEvent:eventType forTarget:nil withSeletorStr:selectorStr andCustomParam:customParam];
}
break;
}
}
從上面代碼發(fā)現(xiàn)匙睹,除了BHMInitEvent
初始化瘩扼、BHMTearDownEvent
析構(gòu)兩個(gè)特殊事件外谆甜,所有的事件都是調(diào)用handleModuleEvent:forTarget:withSeletorStr:andCustomParam:
,在內(nèi)部通過遍歷moduleInstances
數(shù)組集绰,調(diào)用performSelector:withObject:
實(shí)現(xiàn)
- (void)handleModuleEvent:(NSInteger)eventType
forTarget:(id<BHModuleProtocol>)target
withSeletorStr:(NSString *)selectorStr
andCustomParam:(NSDictionary *)customParam
{
BHContext *context = [BHContext shareInstance].copy;
context.customParam = customParam;
context.customEvent = eventType;
if (!selectorStr.length) {
selectorStr = [self.BHSelectorByEvent objectForKey:@(eventType)];
}
SEL seletor = NSSelectorFromString(selectorStr);
if (!seletor) {
selectorStr = [self.BHSelectorByEvent objectForKey:@(eventType)];
seletor = NSSelectorFromString(selectorStr);
}
NSArray<id<BHModuleProtocol>> *moduleInstances;
if (target) {
moduleInstances = @[target];
} else {
moduleInstances = [self.BHModulesByEvent objectForKey:@(eventType)];
}
//遍歷 moduleInstances 實(shí)例數(shù)組规辱,調(diào)用performSelector:withObject:方法實(shí)現(xiàn)對應(yīng)方法調(diào)用
[moduleInstances enumerateObjectsUsingBlock:^(id<BHModuleProtocol> moduleInstance, NSUInteger idx, BOOL * _Nonnull stop) {
if ([moduleInstance respondsToSelector:seletor]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
//進(jìn)行方法調(diào)用
[moduleInstance performSelector:seletor withObject:context];
#pragma clang diagnostic pop
[[BHTimeProfiler sharedTimeProfiler] recordEventTime:[NSString stringWithFormat:@"%@ --- %@", [moduleInstance class], NSStringFromSelector(seletor)]];
}
}];
}
3、BeeHive模塊調(diào)用
通過BHServiceManager
來管理已經(jīng)注冊的Protocol
注冊Protocol
的方式和注冊Module
方式一一對應(yīng)
.plist文件
- 設(shè)置
plist文件路徑
[BHContext shareInstance].serviceConfigName = @"BeeHive.bundle/BHService";
- 創(chuàng)建
plist文件
-
loadStaticServices
方法讀取plist
文件栽燕,存儲到字典中
#pragma mark - Private
//初始化context罕袋,加載Modules、Services
-(void)setContext:(BHContext *)context
{
_context = context;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self loadStaticServices];
[self loadStaticModules];
});
}
//加載Services
-(void)loadStaticServices
{
[BHServiceManager sharedManager].enableException = self.enableException;
[[BHServiceManager sharedManager] registerLocalServices];
}
- (void)registerLocalServices
{
NSString *serviceConfigName = [BHContext shareInstance].serviceConfigName;
//plist文件路徑
NSString *plistPath = [[NSBundle mainBundle] pathForResource:serviceConfigName ofType:@"plist"];
if (!plistPath) {
return;
}
NSArray *serviceList = [[NSArray alloc] initWithContentsOfFile:plistPath];
[self.lock lock];
//遍歷并存儲到allServicesDict中
for (NSDictionary *dict in serviceList) {
NSString *protocolKey = [dict objectForKey:@"service"];
NSString *protocolImplClass = [dict objectForKey:@"impl"];
if (protocolKey.length > 0 && protocolImplClass.length > 0) {
[self.allServicesDict addEntriesFromDictionary:@{protocolKey:protocolImplClass}];
}
}
[self.lock unlock];
}
動(dòng)態(tài)注冊(load)
- 在
load
方法中注冊Protocol
協(xié)議碍岔,通過調(diào)用BeeHive里面的registerService:service:
方法完成注冊
+ (void)load
{
[[BeeHive shareInstance] registerService:@protocol(UserTrackServiceProtocol) service:[BHUserTrackViewController class]];
}
??
- (void)registerService:(Protocol *)proto service:(Class) serviceClass
{
[[BHServiceManager sharedManager] registerService:proto implClass:serviceClass];
}
Annotation注冊
//****** 1浴讯、通過BeeHiveService宏進(jìn)行Annotation標(biāo)記
BeeHiveService(HomeServiceProtocol,BHViewController)
//****** 2、宏定義
#define BeeHiveService(servicename,impl) \
class BeeHive; char * k##servicename##_service BeeHiveDATA(BeehiveServices) = "{ \""#servicename"\" : \""#impl"\"}";
//****** 3蔼啦、轉(zhuǎn)換后的格式榆纽,也是將其存儲到特殊的段
char * kHomeServiceProtocol_service __attribute((used, section("__DATA,""BeehiveServices"" "))) = "{ \"""HomeServiceProtocol""\" : \"""BHViewController""\"}";
獲取Protocol
Protocol
相比Module
,可以返回Protocol實(shí)例對象
- (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是否已經(jīng)注冊過
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;
}
}
//獲取類后奈籽,然后響應(yīng)下層的方法
Class implClass = [self serviceImplClass:service];
if ([[implClass class] respondsToSelector:@selector(singleton)]) {
if ([[implClass class] singleton]) {
if ([[implClass class] respondsToSelector:@selector(shareInstance)])
//創(chuàng)建單例對象
implInstance = [[implClass class] shareInstance];
else
//創(chuàng)建實(shí)例對象
implInstance = [[implClass alloc] init];
if (shouldCache) {
//緩存
[[BHContext shareInstance] addServiceWithImplInstance:implInstance serviceName:serviceStr];
return implInstance;
} else {
return implInstance;
}
}
}
return [[implClass alloc] init];
}
創(chuàng)建service之前,會檢查Protocol是否注冊過
從字典中取出Protocol對應(yīng)的Class
如果實(shí)現(xiàn)了
singleton
方法實(shí)現(xiàn)了
shareInstance
鸵赫,創(chuàng)建單例否則創(chuàng)建實(shí)例對象
將
implInstance
和serviceStr
緩存創(chuàng)建實(shí)例對象
serviceImplClass
方法中衣屏,protocol為key,serviceImp為value存在字典中
- (Class)serviceImplClass:(Protocol *)service
{
//通過字典將 協(xié)議 和 類 綁定辩棒,其中協(xié)議作為key狼忱,serviceImp(類的名字)作為value
NSString *serviceImpl = [[self servicesDict] objectForKey:NSStringFromProtocol(service)];
if (serviceImpl.length > 0) {
return NSClassFromString(serviceImpl);
}
return nil;
}
輔助類
BHConfig
:單例,維護(hù)一些動(dòng)態(tài)的環(huán)境變量一睁,作為BHContext
的補(bǔ)充BHContext
:單例钻弄,內(nèi)部兩個(gè)字典屬性:modulesByName
、servicesByName
者吁,用來保存上下文信息BHTimeProfiler
:計(jì)算時(shí)間性能方面的BHWatchDog
:新開一個(gè)線程斧蜕,監(jiān)聽主線程是否堵塞