1.0 什么是模块化
很多关于重构
及设计模式
的介绍中,经常提到的几个词语是复用
及解耦
。
模块化之所以被提出,也更多是为了解决这几个问题。
复用
可以减少重复造轮子的情况,很容易理解的是,我们经常使用的github上的第三方框架,比如,AFNetworking等,有了这些组件,我们就不需要再写一遍了。
解耦
可以减少类或文件之间的关联,如果一个类引用了其他10个类,那么当我们看到这个类或修改这个类的时候,我们同时需要关注另外10个类,了解它们与本类的关联情况。如果你的类,没有与其他任何类关联,你在阅读代码的时候,完全可以忘记其他代码的存在,只看这一个文件就够了。
我们可以看出,低耦合
的系统,能够将无数简单的模块,组成复杂的工程。复用
很明显能够提升工作效率,解放生产力。
这样一来,你的系统是简单的,清晰的,当你重构或修改系统的时候,可以不必有任何顾虑。
而实现低耦合
和可复用
的手段,往往就称为模块化。
在实际开发中,模块往往被定义为能够独立实现单一任务的代码单元。
从代码角度讲,一个功能,一个文件,一个类,甚至一个函数,都可以成为一个模块。
除了上述优点之外,模块化之后,每个模块可以单独开发,单独测试,也更容易做内部代码的权限管理。
上面已经说过,整个系统都是由不同的模块构成。那么问题的难点就在于,如何定义模块的边界。
2.0 模块的划分及通信
在客户端实际开发中,根据模块的使用方式,可以大致分为2种。
第一种,提供非常基础功能,会频繁地被其他模块引用,其他模块可以直接引入这些模块的api进行调用。比如:网络模块,常用工具类,布局,图片,其他依赖的第三方框架。
第二种,提供有价值的产品功能,更多的是页面的展示接口,它从来不被别的模块直接引用,更多地通过异步的方式来进行通信(使用路由)。比如:会员模块,付费模块,短视频模块等等。
另外,除了这两种模块之外,还有一种模块既会被其他模块频繁地引用,也会提供页面的展示接口。比如:登陆,收藏,关注等功能。这种模块需要为其他模块提供数据及修改接口,有时候还需要展示UI。
其实对于第三种模块来说,可以根据数据和展示,拆分为2个模块:一个模块用于对外部提供数据,可以被其他模块直接引用;另一个模块用于通过异步的方式进行页面的展示。
3.0 iOS模块化的实践方案
3.1 模块化工作流程
iOS中的模块化,不同的模块是通过动态库/静态库的方式引入到主工程中的。
动态库和静态库的区别无需多说,可根据需要自行选择。
cocoapods是一个非常优秀的模块管理工具。
我们使用cocoapods来管理不同的模块时,代码可以以3种存在形式出现,分别是:源码,静态库,动态库。
所以在模块化之前,我们需要提前进行的工作有:
- 安装cocoapods
- 建立pod私有库,用来存储我们所有模块的podspec文件
我们创建一个新模块工作流应该是这样的:
- 建立一个新工程,修改必要设置
- 建立Podfile文件,添加依赖,然后执行pod install安装依赖
- 开始开发工作,开发过程中,你可能需要建立一个Demo工程或者Demo target用于在开发过程中,测试你的静态库api
- 编写单元测试
- 测试通过后,你需要将代码提交到git中,并且打一个tag
- 编写podspec文件
- 检查podspec文件的正确性
- 使用pod repo push命令将podspec文件推到pod私有库中
- 如果其他模块想要引用这个模块,按照pod标准使用方式安装依赖即可
3.2 可能遇到的问题
在上述流程中,可能遇到的问题有:
- podspec文件怎么写?
- podspec文件提交和更新需要怎么做?
- Podfile文件怎么写?
- 如果我开发的模块依赖了我们之前开发的其他的模块该怎么处理?如果我依赖的模块也需要修改,应该怎样处理?
- 产生循环依赖怎么办?A依赖B,B又依赖A。
- 怎样处理图片等资源文件
- 如何进行OC与swift的混编
- framework如何编译,如何减肥,如何合并
4.0 流程自动化
我们可以看到,创建模块化的过程流程比较多,涉及的技术也很多:cocoapods,Xcode设置,资源管理,Swift&OC编译管理,静态库接入方式等等。
其中很多技术内容其实并不常用,在开发过程中,我们遇到问题后,即时查阅文档解决,过了一段时间,遇到同样的问题可能还需要再查阅。
而且,不同的人在实践过程中,可能会遇到相同的问题,每个人都需要解决一次。
流程过多,还容易因为误操作而产生错误,这种问题很难解决,往往遇到就会花费大量时间处理。
我们再回头看一下工作流程,其实很多工作都是固定不变的,每次创建新模块都是重复同样的过程,因此这部分流程我们可以通过自动化脚本自动完成。
我们哪些工作可以使用脚本完成呢?
- 创建
模块工程
及Demo
工程,自动设置里面的Build Setting
选项,并使用.xcworkspace来管理 - 部分内容根据用户输入,自动创建
podspec
文件,并检查其正确性 - 根据用户输入的依赖模块,自动创建不同工程的
Podfile
文件,并使用pod install
安装依赖 - 管理模块目录结构,脚本能够方便的对模块进行增删改查
- 如果某个模块依赖的是我们自己开发的其他模块,那么被依赖的模块会以
local path
的方式引入到工程中,这样我们可以在当前模块的工程中直接修改依赖模块的代码并进行测试,不需要打开多个工程。开发完成后,分别进行提交。 - 自动安装脚本所依赖的软件和环境
- 记录已经push到私有库的模块,方便处理多依赖模块的开发
- 开发完成后,使用脚本一键推送到pod库中
- 对已经在pod库中的模块进行二次开发时,可以一键拉取工程并安装所有依赖
完成上面的功能后,我们可以发现:
- 对于全新的模块,我们可以使用脚本,一键创建工程,然后就可以进行业务开发了,开发之后,只需要再执行一个脚本,就能够推送到私有库中,不需要了解cocoapods和Xcode设置的任何细节。
- 对于二次开发的模块,我们同样适用脚本,一键拉取工程及所有依赖,仅仅关注业务开发即可。开发完成后,同样使用脚本一键推送到私有库中。
--完--