iOS之组件化 五

332 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 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];
    }
}

方案的思路:

image-65.png

  • 模块:模块被不同的功能分开,每个模块都可以通过自己的服务与其他模块进行通信
  • 服务:服务是特定模块的接口
系统事件

系统事件通常是应用程序生命周期事件,如DidBecomeActiveWillEnterBackground

系统事件基本工作流程如下

image-66.png 使用自定义AppDelegate继承于BHAppDelegate,代替系统AppDelegate

@interface TestAppDelegate : BHAppDelegate <UIApplicationDelegate>
通用事件

在系统事件的基础上扩展通用应用程序事件,如modSetupmodInit等,可用于编码每个插件模块的初始化设置

扩展常见事件如下

image-67.png

业务自定义事件

如果觉得系统事件,事件还不能满足一般需求,我们将事件简化打包成BHAppdelgate,可以通过继承BHAppdelegate扩展自己的事件,同时BHContext里的modulesByName访问每个模块入口类,增加触发点通过

[[BHModuleManager sharedManager] triggerEvent:BHMSetupEvent];
模块注册

模块的注册有两种方式:

  • 静态注册
  • 动态注册 静态注册方式:

AppDelegate应用启动时,初始化moduleservice的plist文件

image-68.png 打开BHService.plist,以字典方式将protocolclass对应,需要手动维护

image-69.png 动态注册方式:

使用注解方式,注册protocolclass的对应关系

@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方法,注册protocolclass的对应关系:
- (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];
}