随着时间的推移,任何代码库都会随着项目的发展和成熟而增长。它为开发人员带来了两个主要限制:如何使代码井井有条,同时保持构建时间尽可能短。让我们看看模块化体系结构如何解决该问题
如何在iOS中构建模块化架构 - 图1
xcode库

模组

模块开始,我们可以将其表示为与其他主应用程序隔离的代码资源。然后,将其作为依赖项添加到我们的iOS应用中。

创建模块还可以大大提高代码的可测试性和可重用性。

这种依赖关系可以是应用程序的技术方面(网络,存储等),也可以是功能(搜索,帐户等)来封装复杂性。
定义后,我们就可以开始添加要隔离的代码和资源。
打包代码的方式只有两种:动态框架静态库
两者之间的主要区别在于它们在最终可执行文件中的导入方式。静态库包含在编译类型中,可在可执行文件中进行复制,动态库在可执行文件的运行时包含在其中,而从不复制,因此启动时间更快。

创建一个模块

现在我们知道了什么可以成为模块,让我们创建一个。假设我们为电子商务创建了一个新应用程序,则需要创建一个特定的依赖项,以表示我们应用程序的核心概念。我称它为Core
首先,我创建一个动态框架项目。
如何在iOS中构建模块化架构 - 图2
模块动态框架
由于它是一个电子商务应用程序,因此我们应用程序的核心是由我们销售的产品代表的。让我们为此创建一个简单的对象。

  1. public struct Product {
  2. let name: String
  3. let price: Double
  4. }

由于我们的用户想要浏览产品,因此我们需要一种获取产品的方法。让我们创建一个协议来公开这一点。

  1. public protocol ProductServiceProtocol {
  2. func getAllProducts() -> [Product]
  3. }
  4. public final class ProductService: ProductServiceProtocol {
  5. public init() { }
  6. public func getAllProducts() -> [Product] {
  7. // imagine we fetch products from server
  8. let products = [Product(name: "shoe", price: 100), Product(name: "t-shirt", price: 30)]
  9. return products
  10. }
  11. }

请注意,我们需要定义initpublic,否则internal默认情况下为,这使得它无法从其他导入中使用。
我们的模块已经准备好,让我们将其导入到应用中。

导入模块

创建依赖项后,我们可以将其包含到我们的应用程序中。对于这一部分,我首先创建了一个工作区,这使得一次处理两个项目变得更加容易。
我向工作区以及我的核心模块添加了一个应用程序。它们尚未链接。
为了在应用程序中导入Core框架并能够使用它,我只将框架文件拖放到主应用程序的部分中。Linked Framework and Libraries
如何在iOS中构建模块化架构 - 图3
模块应用
如果构建主应用程序,则可以看到Core也是其中的一部分。太好了,我现在可以使用它。
如何在iOS中构建模块化架构 - 图4
模块应用程序构建
通过一个非常简单的示例,让我们看看是否可以在主应用程序中获取产品。

  1. import Core
  2. class ViewController: UIViewController {
  3. override func viewDidLoad() {
  4. super.viewDidLoad()
  5. let products = ProductService().getAllProducts()
  6. print(products)
  7. }
  8. }

无警告,控制台按预期记录结果。

  1. [Core.Product(name: "shoe", price: 100.0), Core.Product(name: "t-shirt", price: 30.0)]

等等,但是我有很多依赖关系,有些相互联系,我该如何处理它们?
有了更多的模块和依赖项,接下来的问题显然是如何管理它们。让我们来看一些依赖管理器。

依赖经理

为了处理越来越多的依赖关系,我们需要一些方法来对它们进行分组和管理。
让我们从没有依赖项管理器的方法开始幼稚,所有代码在同一项目下的一个仓库中。
如何在iOS中构建模块化架构 - 图5
嵌入式应用
如果它非常适合小型应用程序,那么如果您拥有一个或两个以上的模块,它很快就会变得令人头疼。文件夹将无助于分隔。
进一步采用这种方法,下一步将是在一个工作空间中分离项目。这就是上面演示的解决方案。这是隔离代码并了解代码的可见性和责任的好方法。
如何在iOS中构建模块化架构 - 图6
模块应用
但是,它仍然在同一个git repo下。当项目要扩展时,回购可能会变得很拥挤。还要考虑构建时间:每个依赖项都是使用主应用程序重建的。
让我们尝试分离git repo并使用git子模块。已经更好了,代码可以在其他项目中重用,但是我们仍然受到构建时间的限制。
处理依赖关系的另一个角度是创建一个伞形框架,以将每个依赖关系嵌入到一个程序包中,以限制构建并保持整洁的工作空间。 事实是,如果您使用CocoaPods,您可能已经做到了
如果您查看工作空间并探索Pods项目,它就是处理依赖项的方式。但是,构建时间仍然是瓶颈。
最后,另一个流行的依赖性管理器是Carthage。主要区别在于依赖项是在导入之前构建的。这是保持优化构建的最佳解决方案。
我没有提到Swift Package Manager(或SPM),因为到目前为止它仅可用于macOS。
它们也是Buck或Bazel等其他用于增量构建的新兴解决方案,但这首先要针对连续集成管道。


总之,我们了解了如何将代码隔离到模块中,使其在保持整洁的项目的同时易于重用和测试。可以在此处找到带有模块的示例项目。

推荐👇:

面试题持续整理更新中,如果你想一起进阶,不妨添加一下交流群1012951431
面试题资料或者相关学习资料都在群文件中 进群即可下载!

如何在iOS中构建模块化架构 - 图7