组件化开发的个人理解和实际运用
前言:
上一篇准备工作组件化开发之私有库制作以及常见问题 已经说明了如何去制作私有库并上传,以及私有库podspec文件的一些写法问题,有不清楚的可以通过上述传送门去瞅一瞅,这一篇主要写一下个人对于组件化开发的一些心得和实战记录,后续会附上具体demo以供朋友们阅读,有说的不对的地方也请指出,不要骂我23333,毕竟本人也是菜鸟一枚,自行摸索组件化,难免有些纰漏
体会:
组件化适合多人开发,也是近来比较热门的项目架构设计方式。16年本人便从网上看了些组件化相关的资料,比较经典的是蘑菇街方案蘑菇街App的组件化之路以及蘑菇街的组件化之路.续和@casatwy基于蘑菇街方案的探讨iOS应用架构谈 组件化方案,那时候看不懂啊,脑袋疼,压根儿不理解,后来17年又看了【一缕殇流化隐半边冰霜】的iOS 组件化 —— 路由设计思路分析,以及组件化架构漫谈 结果是对组件化越来越懵逼,对于组件化迟迟不敢下手,找不到入口。
最近想要尝试下组件化到底是一种什么感受,断断续续看了一年多的组件化理论知识,如今终于要开启尝试之旅,心中还是有些忐忑的,于是先去整了私有库相关的一些准备工作,接下来尝试将项目中的一些基础模块,公共模块和功能模块给抽了出来,算是走出了第一步。
理解:
我个人对于组件化的认知比较简单,觉得它就是一种解耦的方式,各人管各自的事情,在多人开发的场景下,这种方式肯定是非常有利于提高开发效率的,个人开发的话有兴趣可以尝试,毕竟是吃力不讨好的事情,比如我吃饱了撑的就来试试~~~
一般项目模块都是耦合很严重的,如下:
初始结构.png
图中的关系错综复杂,各种耦合,看起来也是无可奈何,特别是后期维护,牵一发而动全身,恨不能一键删除推倒重来,这也难不倒思路五花八门的开发者们,于是为了解耦合,有了下一张图:
优化结构.png
但这个还有问题,虽然各个模块之间的耦合解了,但是各个模块还要依赖中间件,中间件也要依赖各个模块,这还是相当于没有解耦,所以与时俱进,有了下一张图:
最终结构.png
这里表示的是只让模块对中间件依赖,中间件完全不依赖任何模块,我们所说的解耦合其实也就是这种效果,如果能做到这种,那么,每个模块的负责人都不用再担心另一个模块如何,只需要和中间层进行沟通即可
对于中间件,网上流行的有三种用法,一种是蘑菇街的URL方法,一种是target-action硬编码的方法,另外一种是protocol方法,我个人采用的是target-action方法,这里就简单介绍一下,而后再结合示例demo具体运用。
一.路由-中间件的定制
同样的,中间件可以作为一个组件单独存在,我这里将以
LWRouter
的私有库方式去管理路由,里面只提供简单的跳转(push
present
)两种交互方式
1. 创建路由组件的私有库,方式参照上篇文章
2. 路由的实现
+ (UIViewController *)router_getControllerFromClass:(NSString *)classNam {
Class class = NSClassFromString(classNam);
return [[class alloc] init];
}
+ (void)router_jumpToDestination:(UIViewController *)destinationVc from:(UIViewController *)sourceVc jumpType:(YGRouterJumpType)jumpType animation:(BOOL)animation params:(id)params {
[self router_jumpToDestination:destinationVc from:sourceVc jumpType:jumpType animation:animation params:params callback:nil];
}
+ (void)router_jumpToDestinationWithName:(NSString *)destination from:(UIViewController *)sourceVc jumpType:(YGRouterJumpType)jumpType animation:(BOOL)animation params:(id)params {
UIViewController *destinationVc = [self router_getControllerFromClass:destination];
[self router_jumpToDestination:destinationVc from:sourceVc jumpType:jumpType animation:animation params:params];
}
+ (void)router_jumpToDestinationWithName:(NSString *)destination from:(UIViewController *)sourceVc jumpType:(YGRouterJumpType)jumpType animation:(BOOL)animation params:(id)params callback:(void(^)(id callback))callback {
UIViewController *destinationVc = [self router_getControllerFromClass:destination];
[self router_jumpToDestination:destinationVc from:sourceVc jumpType:jumpType animation:animation params:params callback:callback];
}
+ (void)router_jumpToDestination:(UIViewController *)destinationVc from:(UIViewController *)sourceVc jumpType:(YGRouterJumpType)jumpType animation:(BOOL)animation params:(id)params callback:(void(^)(id callback))callback {
if (params) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
[destinationVc performSelector:@selector(router_params:) withObject:params];
#pragma clang diagnostic pop
}
if (callback) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
[destinationVc performSelector:@selector(router_callback:) withObject:callback];
#pragma clang diagnostic pop
}
if (jumpType == YGRouterJumpTypePush) {
[sourceVc.navigationController pushViewController:destinationVc animated:animation];
}else {
[sourceVc presentViewController:destinationVc animated:animation completion:nil];
}
}
这里提供了push ,modal两种模式,此外还可以传参以及回传等,有其他情况的另行增加方法即可
二:示例demo的搭建以及结合组件化的过程
项目结构.png示例工程采用tabbar+nav+vc的模式,我这里分为基础层,网络层,应用层和业务层以及路由。基础层主要放一些公共部分和变化不大的的部分,网络层主要管理项目中间的网络请求部分,应用层主要是一些工具类的封装,业务层则是项目的一些业务逻辑部分,前三层基本不依赖彼此,业务层则需要依赖前三层,业务层中分为不同的模块,模块间的交互通信则是通过路由,大致的分配如下图所示:
从图中可以很清晰的看到,层次划分非常的清楚,如果多人配合开发,只需要一个人负责一个模块即可。至于项目中的哪些可以规划到各个层级和模块中就要视具体的情况而定,我这里主要大致说一下自己的理解:
1.比如整个项目中的基类,我这里指的是不变的那些,如导航控制器,这个一般设置后就不需要变化的那种,分类,图片,xib资源,常量类等都可以放到基础层
2.网络层主要放置网络请求,可以使离散的,也可以是集约的。集约型也就是对AFN的二次封装,提供的只是get,post等接口。离散型的,推荐
YTKNetwork
,思想是一个请求一个类,这两者各有优劣,关键看个人取舍。
3.应用层主要放一些功能性的文件,如:支付功能,地图,定位功能,数据库封装等
4.业务层就是做业务功能的,这里可以将每个模块细分为一个私有库方便多人开发时每个人负责一个业务模块去开发。
5.主工程导入各个私有库文件,提供入口即可
- 大致的结构如此,当然这里只是我个人对于模块和层级的理解,如果你有更好的划分方式和心得,欢迎在留言区进行沟通交流。
下面具体讲下过程和引入
1.创建远程仓库并拉取到本地,制作成私有库
屏幕快照 2018-11-19 下午3.16.34.png 屏幕快照 2018-11-19 下午2.48.28.png私有库的制作见前文,这里不再赘述
最终导入项目的结构如下:
屏幕快照 2018-11-19 下午6.46.16.png 屏幕快照 2018-11-19 下午6.55.22.png
2.主工程调用
前面已经提到,组件化比较理想的结构是,主工程中只有入口,也就是我们常用的设置TabBar相关以及一些必要的配置等,其他都在组件私有库中完成,通过上面的结构我们已经实现了拆分功能为私有化组件,接下来就是通过主工程提供入口并组合起来。
Simulator Screen Shot - iPhone 6s Plus - 2018-11-20 at 13.24.37.png
3.模块间的通信与交互
主要通过router,示例代码如下:
传参不带回传参数的:
屏幕快照 2018-11-20 下午1.26.37.png
传参带回传参数的:
屏幕快照 2018-11-20 下午1.26.23.png
若是ModalA和ModalB交互,采用的方式也是如此
具体的使用过程可以通过传送门查看,有关于组件化方面的心得体会可以在评论区进行交流学习,本人也是初次尝试使用,有用的不到的地方或者理解有偏颇的地方,还请海涵,多谢朋友们的指正,大家共同学习,谢谢~~~~