iOS开发 -- 组件化 之 Cocoapods私有库详解

3,091 阅读9分钟

目录如下:

  1. iOS 底层原理探索 之 alloc
  2. iOS 底层原理探索 之 结构体内存对齐
  3. iOS 底层原理探索 之 对象的本质 & isa的底层实现
  4. iOS 底层原理探索 之 isa - 类的底层原理结构(上)
  5. iOS 底层原理探索 之 isa - 类的底层原理结构(中)
  6. iOS 底层原理探索 之 isa - 类的底层原理结构(下)
  7. iOS 底层原理探索 之 Runtime运行时&方法的本质
  8. iOS 底层原理探索 之 objc_msgSend
  9. iOS 底层原理探索 之 Runtime运行时慢速查找流程
  10. iOS 底层原理探索 之 动态方法决议
  11. iOS 底层原理探索 之 消息转发流程
  12. iOS 底层原理探索 之 应用程序加载原理dyld (上)
  13. iOS 底层原理探索 之 应用程序加载原理dyld (下)
  14. iOS 底层原理探索 之 类的加载
  15. iOS 底层原理探索 之 分类的加载
  16. iOS 底层原理探索 之 关联对象
  17. iOS底层原理探索 之 魔法师KVC
  18. iOS底层原理探索 之 KVO原理|8月更文挑战
  19. iOS底层原理探索 之 重写KVO|8月更文挑战
  20. iOS底层原理探索 之 多线程原理|8月更文挑战
  21. iOS底层原理探索 之 GCD函数和队列
  22. iOS底层原理探索 之 GCD原理(上)
  23. iOS底层 - 关于死锁,你了解多少?
  24. iOS底层 - 单例 销毁 可否 ?
  25. iOS底层 - Dispatch Source
  26. iOS底层 - 一个栅栏函 拦住了 数
  27. iOS底层 - 不见不散 的 信号量
  28. iOS底层 GCD - 一进一出 便成 调度组
  29. iOS底层原理探索 - 锁的基本使用
  30. iOS底层 - @synchronized 流程分析
  31. iOS底层 - 锁的原理探索
  32. iOS底层 - 带你实现一个读写锁
  33. iOS底层 - 谈Objective-C block的实现(上)
  34. iOS底层 - 谈Objective-C block的实现(下)
  35. iOS底层 - Block, 全面解析!
  36. iOS底层 - 启动优化(上)
  37. iOS底层 - 启动优化(下)
  38. iOS底层原理探索 -- 内存管理 之 内存五大区
  39. iOS底层原理探索 -- 内存管理 之 Tagged Pointer Format Changes
  40. iOS底层原理探索 -- 内存管理 之 retain & release
  41. iOS底层原理探索 -- 内存管理 之 弱引用表
  42. iOS底层原理探索 -- 内存管理 之 @autoreleasepool
  43. iOS底层原理探索 之 RunLoop 概念

以上内容的总结专栏


细枝末节整理


写在前面: iOS底层原理探究是本人在平时的开发和学习中不断积累的一段进阶之
路的。 记录我的不断探索之旅,希望能有帮助到各位读者朋友。

前言

随着公司业务的不断发展,团队不断壮大的同时,项目也随之臃肿起来,如何保障团队协作的高效,自然的想到了组件化这个话题。下面总结下本人的梳理和思考。

组件化

  • 为什么我们需要组件化 项目模块间的解耦、模块实现可重用、提升团队成员之间团队之间的协作开发效率、更方便单元测试。

  • 并不是所有的项目都适合组件化 如果你的项目较小,模块之间交互简单,耦合很少;模块没有被外部模块引用,只是一个单独的小模块;模块不需要重用,代码也很少被修改;团队规模很小。那么,你对项目就没有必要做组件化。


如果你的项目有以下三个特征以上,就要考虑下进行组件化了:

  1. 模块逻辑复杂,多个模块之间频繁互相引用
  2. 项目规模逐渐变大修改代码变的越来越困难(这里可以理解为:修改一处代码,需要同时修改其他多个地方);
  3. 团队人数变多,提交的代码经常和其他成员冲突
  4. 项目编译耗时较长
  5. 模块的单元测试经常由于其他模块的修改失败

  • 组件化的8条指标

一个项目经过组件化后如何来评判项目组件化是否彻底或者说是否优秀,可以通过以下几个方面:

  1. 模块之间没有耦合,模块内部的修改不影响其他模块;
  2. 模块可以单独编译
  3. 模块间数据传递明确
  4. 模块可以随时被另一个提供了相同功能的模块替换
  5. 模块对外接口清晰且易维护;
  6. 模块接口改变时,此模块的外部代码能够被高效重构
  7. 尽量用最少的修改和代码,让现有的项目实现模块化;
  8. 支持OC和Swift,以及混编。

前4条主要用于衡量一个模块是否真正解耦后4条主要用于衡量在项目实践中的易用程度

组件化分层

一般一个项目主要分为三层:业务层、通用层、基础层

组件化分层.001.jpeg

组件化封层之后,需要遵循一下原则:

  1. 只能 上层对下层 依赖, 不能 下层对上层 依赖(下层是对上层的抽象);
  2. 项目公共代码资源下沉;
  3. 横向的依赖尽量少有,最好下称到通用模块或者基础模块。

组件化方案

目前常用的组件化方案主要有两种:

  • 本地组件化: 主要是通过在 工程中创建 library, 利用 cocoapods 的 workspec 进行 本地管理, 不需要将项目上传git,而是直接在项目中以 framework 的方式 进行调用。

  • cocoapods组件化:主要是利用 cocoapods 来进行 模块的远程管理,需要将项目上传 git (这里的组件化模块分为 公有库 和 私有库 , 对公司而言, 一般是私有库)

本地组件化

  1. 创建主工程
  • 新建项目主工程
  • 集成 cocoapods , 进行本地管理,执行命令 pod init
  • 编辑 Podfile, 并执行 pod install
  1. 创建组件

可以创建 自己的模块:

  • 主工程:主要实现表层业务代码
  • Base:基类封装
  • Tools:工具(字符串,颜色,字体等)
  • Service:服务层,封装业务工具类,例如网络层服务、持久化服务等
  • Pods:第三方依赖

其中,各个模块间的关系如下所示:

Local模块间的关系.001.jpeg

cocoapods组件化

下面我们开始组件化的一些概念学习:远程索引库、本地索引库、远程代码库、本地代码库; 我们逐一进行介绍。

远程索引库

概念:每创建一个组件都会带一个 xxx.podspec 的索引文件。专门用来存放这些索引文件的库就叫做索引库。我们需要将这些索引文件上传到远程索引库才能保证其他的同事能够拿来用。

我们接下来就创建远程索引库: 登录GitHub

image.png image.png

本地索引库

与远程索引库对应,本地索引库用来存放本地索引文件的库。

创建本地索引库:

  1. 打开终端,通过命令 pod repo 查看你本地已经有哪些本地索引库(这里我已经添加了 WJHSpecs 所以可以看到有),

image.png

  1. 通过 pod repo add 本地索引库的名字 远程索引库的地址 命令 创建本地索引库并和远程索引库做关联(注:本地索引库的名字建议和远程索引库起的名字一样)

  2. 在Finder中如下路径已经可以看到创建成功。 image.png

远程代码库

用来存放准备组件化的代码,创建方式和创建远程索引库方式一样。这里我们把 自己整理的 相关代码组件化,我们创建一个 WJHBaseWidgets 的远程代码库。

  1. 如下图:

image.png

本地代码库

我们在这里 创建 WJHBaseWidgets 本地代码库

pod lib creat 组件名

注意这里创建本地代码库是可以选择路径的,也就是说你想创建在哪里(cd 到路径就可以),后面会用到路径。

pod lib create WJHBaseWidgets

image.png

  • 之后会创建一个工程,目录如下

注意这个工程就在你创建代码库路径下

image.png

  • 编译成功之后,把我们 自己整理的 组件化相关的代码 拖入到本地代码库下面路径

添加组件化代码到 Classes 文件夹

image.png

  • Classes 中的文件修改后,我们cd到Example下进行 pod install (刚才添加到 Classes 中的文件夹 pod 进来)

image.png

修改 podspec 文件

  • 编译组件不报错的话,开始修改 podspec 文件: 一般修改一下几个内容:
  1. 修改版本号

  2. 修改项目的简单概述和详细概述

  3. 修改 homepage 和 source 地址

  4. 添加依赖库

image.png

编译通过之后,提交组件到远程代码库 并 打tag

  • git add .
  • git commit -m "description"
  • git remote add origin 远程代码仓库地址
  • git push origin master
  • git tag 版本号 (注:这里的版本号必须和 podspec 里写的版本号一致)
  • git push --tags

验证podspec索引文件

通过 pod spec lint --verbose --allow-warnings --use-libraries 命令验证 podspec 索引文件

提交索引文件到远程索引库

验证通过之后, pod repo push 本地索引库 索引文件名 --verbose --allow-warnings --use-libraries 提交索引文件到远程索引库。

pod repo push WJHSpecs WJHBaseWidgets.podspec --verbose --allow-warnings --use-libraries

在 Finder 中可以查看是否成功

image.png

使用组件化代码

使用的话和通过 cocoapods 引入第三方一样, 在需要引入改组件的工程里修改 Podfile。

Podfile文件修改如下:

image.png

pod install 后, 项目中就把 WJHBaseWidgets 组件 pod 到项目中了。

image.png

报错解决

ERROR | xcodebuild: *** /BaseModel.h:13:9: error: include of non-modular header inside framework module 'wLib.BaseModel' [-Werror,-Wnon-modular-include-in-framework-module]

出现场景:pod验证podspec文件的时候,如果.h文件里面有引用第三方pod,会出现这个错误

解决方式:在命令后面添加 --use-libraries 就可以了 (本篇文章中的校验和提交均以添加)