LipYoung / programing-blog

个人中文编程博客。
MIT License
3 stars 0 forks source link

通过xcworkspace和Cocoapods实现XCode项目模块化 #6

Open LipYoung opened 5 years ago

LipYoung commented 5 years ago

我想做什么

在项目开发早期构建较多的模块,每一个模块负责独立的功能.例如将一个待办事项类应用分为主工程,数据库存储两部分.

解决了什么问题

这样做能让项目更清晰,有条理.而且因为独立的出的模块是独立编译后嵌入主工程内,在独立出的模块足够多且未修改的情况下可以大幅度的减少增量编译速度.

还有比较重要的一点是,独立出的模块可以单独添加单元测试以及测试覆盖率检查工具,达到增加模块健壮性稳定性,在项目的后期也可以顺利的发布为独立的模块给更多的项目使用.(这里有一篇文章介绍了如何使用 Cocoapods 发布模块 #2 )

较常见的工程现状

现状

使用XCode默认生成的项目.使用 XCode 打开 SomeApp.xcodeproj 如图:

f0cf2857-ffc9-41b2-b2c9-da40dbcf707a

如果有使用三方的需求则通过 (Cocoapods)[] 管理三方库,然后使用 Cocoapods 自动生成的 Catnip.xcworkspace.

4890a259-9399-4653-a056-22eba455128b

模块化后工程目录

dda5a986-6f28-43a2-876e-d60b5abfb388

图片依次为 Catnip主工程 独立的模块 WhiteMilk, Cocoapods 管理的工程 Pod 以及 Cocoapods 生成的虚拟目录 WhiteMilk.(两个WhiteMilk是指向了同一个真实文件,且完全一致)

如何做到

示例环境
XCode: 10.0
Cocoapods: 1.5.3
Swift: 4.2
前置条件:
在开始之前:
1. 需要你会熟练使用 XCode 的常规操作.例如构建新工程.
2. 需要你会熟练使用 Cocoapods 的常规操作.例如为旧项目集成 Cocoapods.
3. 需要你了解一些基础的 Swift 知识.

1. 创建,链接以及嵌入 framework

a. 创建 framework 比较简单和创建一个工程的方式一致,通过 XCode 选择即可. 129eac50-e2eb-454b-90c8-76deab442e6c

b. 添加新建的 framework 在创建后选择保存的位置时勾选上已有的工程. 58d43c21-7a99-4c5b-a695-08c5521b642a

c. 如果是添加已有的 framework 则通过在需要被嵌入的工程内选择 Add File's,然后选中已存在工程. 642be90a-d0cf-4248-b60d-ea4e08e8a9cf

62b4043b-fc91-48e6-afef-03cb59613706

d. 最后一步,通过 General -> Embedded Binaries 选择新建的或者已有的 framework到链接(Linked)和嵌入(Embedded)到工程内.这样在正式编译执行时链接已有的 framework. b09cc3dc-00ff-4fe3-9517-9fd07b6498ec

注意事项

A. 首先尽量选择使用 framework 而不是 static Library .后者一般被翻译为静态库也常被叫做.a文件.使用静态库的方式组织的文件,如果多次被重复链接会导致错误.举个例子: A工程包含M1模块和M2模块,同时M1,M2还有A工程都需要使用到一个StaticLib库,静态库本身是已编译好的二进制文件,嵌入链接静态库的本质是复制粘贴,这会导致最后执行的A工程内3个地方都复制了相同的一份二进制文件,同时被链接编译,会导入重复载入的错误.

B. 最后一步一定要通过 Embedded Binaries 进行添加,如果只进行了链接未执行嵌入,那么报错的方式会非常奇怪,你将可以正常的编译工程,运行到模拟器或者真机环境,但是会在开始运行前程序崩溃,抛出dyld__abort_with_payload Thread 1: signal SIGABRT的错误

C. 三方库支持的iOS版本要高于核心工程.

2. 通过 Cocoapods 管理 framework 的依赖

顺序完成了上一步后,以及达到了模块化的目的.可以正常的编写代码,执行.当然实际的开发的情况总是会更复杂,如果需要拆分出的 framework 需要其余一些 别的 framework 才能工作,建议选择 Cocoapods 的解决方案.感谢 Cocoapods 这个伟大的工具,我们只需要通过编写 Podfile 内设置,即可达到适配任意复杂的模块相互依赖情况.

a. 目前的 Demo 工程的依赖情况是主工程(Catnip)依赖了部分常见的库,且只兼容 iOS10以及以上环境. d3bb8c66-7001-4f30-ba18-75ccc6a06134

b. 添加自定义模块(WhiteMilk) 1a3cfdba-b97e-4b56-9167-88eb4934a801

c. 添加工作空间明确指明工作情况的依赖情况 4958f0ae-8b3a-408c-9870-27465ce3b321

d. 为自定义模块(WhiteMilk)添加依赖的三方库SwiftSoup.且修改成 .framework 格式依赖三方库 74e2b4f0-a413-4026-a91c-3419c54af4e5

注意事项

这里只是提供了一种思路,Cocoapods 本身提供了高度自定义的配置方式,可以通过官方文档查阅.

3. 测试

至此,独立模块已通过 framework 方式拆分完毕,也通过 Cocoapods 负责管理各个工程和模块的依赖问题.最后只需要添加测试代码,检查运行结果即可

ac511b10-782e-4f53-b313-49209409ff09

注意:

在每次编译运行测试时,XCode 自身会缓存已部分内容增加编译速度,也就是常说的增量编译.为避免缓存导致掩盖部分错误或者异常错误,在执行本章提到的操作时建议每次都清理缓存(command + shift + K),重新安装pod($pod install)后再行编译运行.

如果有疑问或者相关问题请留言(当然需要你已经有账号且登录了Github).如果本篇博客对你有所帮助请点赞.

点赞方式如图😊: 0d5e309f-4801-4a87-9685-de45e3eb2f5f

GorCat commented 5 years ago

坐等解决 2 个 WhiteMilk 的问题

LipYoung commented 5 years ago

https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPFrameworks/Tasks/CreatingFrameworks.html

官方文档链接