一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第18天,点击查看活动详情。
protocol
将protocol
和对class
进行匹配,过用protocol
获取class
,动态创建实例
方案的代表框架:BeeHive
最基本的使用
//1、创建Protocol
#import <Foundation/Foundation.h>
#import "BHServiceProtocol.h"
@protocol TradeServiceProtocol <NSObject, BHServiceProtocol>
@property(nonatomic, strong) NSString *itemId;
@end
//2、动态创建Module,将protocol和对class进行匹配
@interface TradeModule()<BHModuleProtocol>
@end
@implementation TradeModule
+ (void)load
{
[BeeHive registerDynamicModule:[self class]];
}
- (id)init{
if (self = [super init])
{
NSLog(@"TradeModule init");
}
return self;
}
-(void)modInit:(BHContext *)context
{
NSLog(@"模块初始化中");
NSLog(@"%@",context.moduleConfigName);
id<TradeServiceProtocol> service = [[BeeHive shareInstance] createService:@protocol(TradeServiceProtocol)];
service.itemId = @"我是单例";
}
- (void)modSetUp:(BHContext *)context
{
[[BeeHive shareInstance] registerService:@protocol(TradeServiceProtocol) service:[BHTradeViewController class]];
NSLog(@"TradeModule setup");
}
- (void)basicModuleLevel
{
}
@end
//3、外部调用
-(void)click:(UIButton *)btn
{
id<TradeServiceProtocol> obj = [[BeeHive shareInstance] createService:@protocol(TradeServiceProtocol)];
if ([obj isKindOfClass:[UIViewController class]]) {
obj.itemId = @"12313231231";
[self.navigationController pushViewController:(UIViewController *)obj animated:YES];
}
}
方案的思路:
- 模块:模块被不同的功能分开,每个模块都可以通过自己的服务与其他模块进行通信
- 服务:服务是特定模块的接口
系统事件
系统事件通常是应用程序生命周期事件,如DidBecomeActive
、WillEnterBackground
等
系统事件基本工作流程如下
使用自定义AppDelegate
继承于BHAppDelegate
,代替系统AppDelegate
@interface TestAppDelegate : BHAppDelegate <UIApplicationDelegate>
通用事件
在系统事件的基础上扩展通用应用程序事件,如modSetup
、modInit
等,可用于编码每个插件模块的初始化设置
扩展常见事件如下
业务自定义事件
如果觉得系统事件,事件还不能满足一般需求,我们将事件简化打包成BHAppdelgate
,可以通过继承BHAppdelegate
扩展自己的事件,同时BHContext
里的modulesByName
访问每个模块入口类,增加触发点通过
[[BHModuleManager sharedManager] triggerEvent:BHMSetupEvent];
模块注册
模块的注册有两种方式:
- 静态注册
- 动态注册 静态注册方式:
在AppDelegate
应用启动时,初始化module
和service
的plist文件
打开BHService.plist
,以字典方式将protocol
和class
对应,需要手动维护
动态注册方式:
使用注解方式,注册protocol
和class
的对应关系
@BeeHiveService(UserTrackServiceProtocol,BHUserTrackViewController)
#define BeeHiveService(servicename,impl) \
class BeeHive; char * k##servicename##_service BeeHiveDATA(BeehiveServices) = "{ \""#servicename"\" : \""#impl"\"}";
#define BeeHiveDATA(sectname) __attribute((used, section("__DATA,"#sectname" ")))
- 通过对
section
的操作,将名字写入到__DATA
段 对数据段的读取时机
__attribute__((constructor))
void initProphet() {
_dyld_register_func_for_add_image(dyld_callback);
}
- 在
dyld
注册函数添加到image
的时候,调用dyld_callback
回调函数 进入dyld_callback
函数
{
NSArray *mods = BHReadConfiguration(BeehiveModSectName, mhp);
for (NSString *modName in mods) {
Class cls;
if (modName) {
cls = NSClassFromString(modName);
if (cls) {
[[BHModuleManager sharedManager] registerDynamicModule:cls];
}
}
}
//register services
NSArray<NSString *> *services = BHReadConfiguration(BeehiveServiceSectName,mhp);
for (NSString *map in services) {
NSData *jsonData = [map dataUsingEncoding:NSUTF8StringEncoding];
NSError *error = nil;
id json = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error];
if (!error) {
if ([json isKindOfClass:[NSDictionary class]] && [json allKeys].count) {
NSString *protocol = [json allKeys][0];
NSString *clsName = [json allValues][0];
if (protocol && clsName) {
[[BHServiceManager sharedManager] registerService:NSProtocolFromString(protocol) implClass:NSClassFromString(clsName)];
}
}
}
}
}
- 读取该表头下的所有数据,循环注册模块和服务
代码注册服务:
使用registerService
方法,注册protocol
和class
的对应关系:
- (void)modSetUp:(BHContext *)context
{
[[BeeHive shareInstance] registerService:@protocol(TradeServiceProtocol) service:[BHTradeViewController class]];
NSLog(@"TradeModule setup");
}
异步加载:
如果模块设置为export BH_EXPORT_MODULE(YES)
,会初始化异步执行模块,可以优化后启动前第一屏显示内容启动耗时
服务调用
通过protocol
获取class
-(void)click:(UIButton *)btn
{
id<TradeServiceProtocol> obj = [[BeeHive shareInstance] createService:@protocol(TradeServiceProtocol)];
if ([obj isKindOfClass:[UIViewController class]]) {
obj.itemId = @"12313231231";
[self.navigationController pushViewController:(UIViewController *)obj animated:YES];
}
}
进入createService
方法
- (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;
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;
}
}
// 问题: app -> VC
// serivceProtocol : 普通 绑定在类
// mudleProtocol -> 一点对多的事件 applegate 生命广播不知道
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];
}