小知识,大挑战!本文正在参与“程序员必备小知识”创作活动
为什么需要组件化
- 模块间解耦
- 模块重用
- 提高团队协作开发效率
- 单元测试
组件化的原则
- 只能上层对下层依赖
- 项目的公共代码资源下沉
- 横向的依赖最好下沉
cocoaPods管理组件化分层
cd到测试目录,pod lib create TSHomeModule,接下来选择平台、语言等等按需配置。
-
创建完成之后会自动打开这个项目,发现这个项目什么也没有,Pods里面为空。
-
编写代码,创建好之后自动打开的其实是
TSHomeModule中的EXample的工程,我们需要分层的代码需要写在下图框起来的ReplaceMe这里。
- 添加需要分层的代码
5.回到上面的Example目录下pod install,此时刚才添加的文件就被引入进来了。
- 运行发现报错,原因是有一些用到的第三方没有被引入进来,在Example工程的Pod文件加入配置依赖
- 重新
pod install
- 运行报错,发现还有自己写的分类的扩展没有加进来。以本文的例子继续走起~
- 把分类添加到需要依赖使用分类的地方
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
ModuleA是CTMediator的分类,里面只掌管模块A的逻辑,假如我要跳转到A, 此时在A内重写中间管理层CTMediator的方法performTarget:action:params:这个方法,因为这个方法可以根据模块来自定义- 重写的Target其实最终都是定位到了
Target_A,在这里面响应了action
组件化BeeHive解耦
面向协议,重写了系统的UIAppDelegate。来到main函数,发现是自定义的TestAppDeledate继承于BHAppDelegate
- 1对多分发问题
- (void)applicationWillResignActive:(UIApplication *)application
{
[[BHModuleManager sharedManager] triggerEvent:BHMWillResignActiveEvent];
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[[BHModuleManager sharedManager] triggerEvent:BHMDidEnterBackgroundEvent];
}
- 组件通讯-静态注入
registerLocalServices
[[BeeHive shareInstance] setContext:[BHContext shareInstance]];
实际上加载的也就是一个plist文件,里面的
service是协议,impl是VC
NSString *protocolKey = [dict objectForKey:@"service"];
NSString *protocolImplClass = [dict objectForKey:@"impl"];
- 组件通讯-动态注入类
**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或动态共享库)时调用
最后动态和静态都绑定之后该数组的成员有: