Loading...
墨滴

weak_PG

2021/10/02  阅读:37  主题:极客黑

面试必问的组件化,你知道多少?

为什么需要组件化

  1. 模块间解耦
  2. 模块重用
  3. 提高团队协作开发效率
  4. 单元测试 ​

组件化的原则

  • 只能上层对下层依赖
  • 项目的公共代码资源下沉
  • 横向的依赖最好下沉 ​

cocoaPods管理组件化分层

  1. cd到测试目录,pod lib create TSHomeModule,接下来选择平台、语言等等按需配置。
  1. 创建完成之后会自动打开这个项目,发现这个项目什么也没有,Pods里面为空。

  2. 编写代码,创建好之后自动打开的其实是TSHomeModule中的EXample的工程,我们需要分层的代码需要写在下图框起来的ReplaceMe这里。

  1. 添加需要分层的代码

5.回到上面的Example目录下pod install,此时刚才添加的文件就被引入进来了。

  1. 运行发现报错,原因是有一些用到的第三方没有被引入进来,在Example工程的Pod文件加入配置依赖
  1. 重新pod install
  1. 运行报错,发现还有自己写的分类的扩展没有加进来。以本文的例子继续走起~

  2. 把分类添加到需要依赖使用分类的地方

cocoaPods管理踩坑-组件化文件资源加载

如果有静态图片资源需要加载的话,我们想当然的就认为应该放在Classes上面的Assets里

但是如果资源放在这里的话,那么我们在Example使用[UIImage imageNamed:]该方法时需要指定资源的路径,这里同时需要新增下配置消息

NSString *bundlePath = [[NSBundle bundleForClass:[self class]].resourcePath stringByAppendingPathComponent:@"/TSModuleTest.bundle"];
NSBundle *resoure_bundle = [NSBundle bundleWithPath: bundlePath];
self.imageView.image = [UIImage imageNamed:@"share_wechat" inBundle:resoure_bundle compatibleWithTraitCollection:nil];

其它的资源比如json文件和xib等等都如此处理。 ​

组件化CTMediator解耦

Target-Action:假如外层要访问ModuleA

  1. ModuleACTMediator的分类,里面只掌管模块A的逻辑,假如我要跳转到A, 此时在A内重写中间管理层CTMediator的方法performTarget:action:params:这个方法,因为这个方法可以根据模块来自定义
  2. 重写的Target其实最终都是定位到了Target_A,在这里面响应了action

组件化BeeHive解耦

面向协议,重写了系统的UIAppDelegate。来到main函数,发现是自定义的TestAppDeledate继承于BHAppDelegate

  1. 1对多分发问题
- (void)applicationWillResignActive:(UIApplication *)application
{
    [[BHModuleManager sharedManager] triggerEvent:BHMWillResignActiveEvent];
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    [[BHModuleManager sharedManager] triggerEvent:BHMDidEnterBackgroundEvent];
}
  1. 组件通讯-静态注入registerLocalServices
[[BeeHive shareInstance] setContext:[BHContext shareInstance]];

实际上加载的也就是一个plist文件,里面的service是协议,impl是VC

NSString *protocolKey = [dict objectForKey:@"service"];
NSString *protocolImplClass = [dict objectForKey:@"impl"];
  1. 组件通讯-动态注入类registerService:implClass:
  // HomeServiceProtocol & homeVc
    // 什么时候建立的绑定  :
    id<HomeServiceProtocol> homeVc = [[BeeHive shareInstance] createService:@protocol(HomeServiceProtocol)];

通过这个协议就能找到指定的类Class implClass = [self.service ImplClass:service];

@BeeHiveService(HomeServiceProtocol,BHViewController)
#define BeeHiveService(servicename,impl) \
class BeeHive; char * k##servicename##_service BeeHiveDATA(BeehiveServices) = "{ \""#servicename"\" : \""#impl"\"}";

#define BeeHiveDATA(sectname) __attribute((used, section("__DATA,"#sectname" ")))

这个宏拆开来就是

class BeeHive; 
char * kHomeServiceProtoco_service __attribute((used, section("__DATA,"BeehiveServices" "))) = 
    "{ \""HomeServiceProtocol"\" : \""BHViewController"\"}";

__DATA通过对section段直接写入,然后在_dyld_register_func_for_add_image回调里面去读取,关于这个方法可以在OC底层应用程序加载流程中的dyld的源码一窥究竟。 _dyld_register_func_for_add_image注册指定的函数,以便在为当前程序的每个映像添加新映像(bundle或动态共享库)时调用。

最后动态和静态都绑定之后该数组的成员有:

weak_PG

2021/10/02  阅读:37  主题:极客黑

作者介绍

weak_PG