序言
对于一款成熟的App来说,持续迭代带来的功能膨胀,不同开发者的编码习惯差异,必然导致代码管理成为一大重要课题。如何更高效率地进行分工合作,如何在团队需要的时候快速回滚代码,这些都是需要研究的,在我看来,组件化便是对这些场景的一个良好解决方案。
组件化的优缺点
组件化即是将代码按照功能/场景拆分,做成不同的组件分别维护。
优点:
- 代码耦合少,方便维护
- 分工更明确,方便分配人员
- 灵活,组件可以在不同App中使用
- 回滚方便
缺点:
- 前期设计工作繁杂,不适合快速试错场景
- 发版流程冗长,需要通过脚本配合
CocoaPods
CocoaPods是iOS上一个比较有名的类库管理工具,绝大部分的开源库都可以通过它来进行集成。另外,它也支持开发者自行创建私有库来集成。业界常用的组件化方案即是使用CocoaPods来创建组件库,然后集成。让我们简单看一下如何使用CocoaPods创建一个私有库。
1.创建私有库
新建一个lib文件夹,并且在该目录下使用命令
pod lib create 私有库名称
然后跟随着指示选择符合自己情况的选项。
CocoaPods会在当前目录下创建一个目录BlogPart,在该目录下有一个BlogPart.podspec文件,里面有着该私有库的一些配置,内容如图所示。
可以看到最后一行s.source_files的值,意味着私有库的源文件全部来自于BlogPart/Classes目录下。在该目录中,可以找到有一个ReplaceMe.m的文件,把该文件删除,并且把真正需要放入私有库的文件放在此目录下即可。
我在该目录添加了BPViewController.h和BPViewController.m文件。
另外,在lib/BlogPart/Example目录下有该私有库的样例工程,查看样例工程目录下的Podfile文件,可以看到pod库的位置为../目录下的BlogPart,即引用了刚刚创建的本地的私有库路径。
在样例工程目录执行以下命令,即可将BlogPart私有库添加到样例工程中去。
pod install
可以看见工程中包含了BPViewController.h和BPViewController.m文件。
2.发布私有库
首先在git上添加自己的私有仓库
将整个BlogPart工程推送到该仓库中,执行以下命令。
git remote add origin 仓库地址
git add .
git commit -a -m 'init'
git tag -a 0.1.0 -m 'init'
git push -u origin master
git push --tags
其中0.1.0为tag版本号,要与BlogPart.podspec中的s.version保持一致
将BlogPart.podspec中的s.source和s.homepage替换成对应该私有仓库的地址,并且使用以下命令添加git私有仓库。
pod repo add 私有库名称 仓库地址
然后使用以下命令检测私有库是否满足发布要求
pod spec lint 私有库名称.podspec
如果通过,则会显示如下结果。
此时私有库满足发布要求,便可以按照以下步骤发布。
pod repo push 私有库名称 私有库名称.podspec
可以看到如下结果,表示发布成功
3.使用私有库
创建一个iOS项目,并且使用命令
pod init
该项目会被转化为一个包含CocoaPods的项目,编辑目录下的Podfile文件。
添加相关的source
source 私有库地址
在target下添加引入的pod库
pod 'BlogPart','~> 0.1.0'
如图所示
随后在该目录使用命令
pod install
打开项目即可看到之前创建的私有库已被引入。
组件化思路
我们平时设计一个App时就会将各个业务模块分开解耦,而组件化其实就是将这些模块打包做成组件。
结构
一般而言,App的代码可以分为五个部分,如图所示。
通用服务组件
这一部分一般存放一些IO、数据库读写、网络传输等代码。通用UI组件
这一部分一般存放一些不涉及具体业务的通用UI控件,例如按钮、单选控件等。业务组件
这一部分一般存放涉及到具体业务的UI控件、以及调用通用UI组件和通用服务组件的代码。
这一部分根据实际情况,可能会再分一层。基础框架组件
这一部分一般存放App中用到的各种容器类,处理模块之间切换的交互,通信等。App
这一部分负责处理业务与容器类的关系。
按照这样的分层方式,各个组件各司其职,代码条理就会更加清晰透彻,容易维护。
如果想要改变整个App的结构,只需要去修改基础架构部分和App部分。
如果想要改变某个业务的逻辑,只需要更改业务部分。
如果想要改变整体的风格,改变部分控件的样式,只需要修改通用UI组件。
如果想要底层某个通信协议需要更改,也只需要修改通用服务组件即可。
通信
不过就如前文提到的,分层越多,组件之间的通信、交互就是一个很大的问题,一旦设计的不好,不仅是修复Bug的时候追溯源头困难,本身开发效率也会十分低下。
我尝试过以下三种通信方案。
各个组件通过Block或者Protocol来与高层组件进行交互。
此方案需要大量代码来制定不同场景需要的不同规则。各个组件通过Notification的方式来与高层组件进行交互。
此方案维护Notification表上会花费较多时间,并且Notification没有编译器检测。将部分接口下沉到下层,通信全部通过调用下层接口,实际实现通过上层组件的Category来替换。
此方案需要的代码较少,但是容易发生一些Category相互替换导致的Bug。
每个方案都各有利弊,实际开发还是需要权衡实际情况进行选择。
总结
iOS组件化可以拿出来深挖的东西太多了,限于篇幅的局限,本文仅作抛砖引玉用。