常用的组件化方案有哪些?

2,449 阅读3分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动

为什么需要组件化

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

组件化的原则

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

cocoaPods管理组件化分层

  1. cd到测试目录, pod lib create TSHomeModule,接下来选择平台、语言等等按需配置。

image.png

  1. 创建完成之后会自动打开这个项目,发现这个项目什么也没有,Pods里面为空。

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

image.png

  1. 添加需要分层的代码

image.png

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

  1. 运行发现报错,原因是有一些用到的第三方没有被引入进来,在Example工程的Pod文件加入配置依赖

image.png

  1. 重新pod install

image.png

  1. 运行报错,发现还有自己写的分类的扩展没有加进来。以本文的例子继续走起~

image.png

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

image.pngimage.png

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

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

image.png

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

image.png

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 image.png

  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]];

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

NSString *protocolKey = [dict objectForKey:@"service"];
NSString *protocolImplClass = [dict objectForKey:@"impl"];

image.png

  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或动态共享库)时调用

image.png image.png

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

image.png