随着时间的推移,任何代码库都会随着项目的发展和成熟而增长。它为开发人员带来了两个主要限制:如何使代码井井有条,同时保持构建时间尽可能短。让我们看看模块化体系结构如何解决该问题。
xcode库
模组
从模块开始,我们可以将其表示为与其他主应用程序隔离的代码资源。然后,将其作为依赖项添加到我们的iOS应用中。
创建模块还可以大大提高代码的可测试性和可重用性。
这种依赖关系可以是应用程序的技术方面(网络,存储等),也可以是功能(搜索,帐户等)来封装复杂性。
定义后,我们就可以开始添加要隔离的代码和资源。
打包代码的方式只有两种:动态框架和静态库。
两者之间的主要区别在于它们在最终可执行文件中的导入方式。静态库包含在编译类型中,可在可执行文件中进行复制,动态库在可执行文件的运行时包含在其中,而从不复制,因此启动时间更快。
创建一个模块
现在我们知道了什么可以成为模块,让我们创建一个。假设我们为电子商务创建了一个新应用程序,则需要创建一个特定的依赖项,以表示我们应用程序的核心概念。我称它为Core。
首先,我创建一个动态框架项目。
模块动态框架
由于它是一个电子商务应用程序,因此我们应用程序的核心是由我们销售的产品代表的。让我们为此创建一个简单的对象。
public struct Product {
let name: String
let price: Double
}
由于我们的用户想要浏览产品,因此我们需要一种获取产品的方法。让我们创建一个协议来公开这一点。
public protocol ProductServiceProtocol {
func getAllProducts() -> [Product]
}
public final class ProductService: ProductServiceProtocol {
public init() { }
public func getAllProducts() -> [Product] {
// imagine we fetch products from server
let products = [Product(name: "shoe", price: 100), Product(name: "t-shirt", price: 30)]
return products
}
}
请注意,我们需要定义init
为public
,否则internal
默认情况下为,这使得它无法从其他导入中使用。
我们的模块已经准备好,让我们将其导入到应用中。
导入模块
创建依赖项后,我们可以将其包含到我们的应用程序中。对于这一部分,我首先创建了一个工作区,这使得一次处理两个项目变得更加容易。
我向工作区以及我的核心模块添加了一个应用程序。它们尚未链接。
为了在应用程序中导入Core框架并能够使用它,我只将框架文件拖放到主应用程序的部分中。Linked Framework and Libraries
模块应用
如果构建主应用程序,则可以看到Core也是其中的一部分。太好了,我现在可以使用它。
模块应用程序构建
通过一个非常简单的示例,让我们看看是否可以在主应用程序中获取产品。
import Core
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let products = ProductService().getAllProducts()
print(products)
}
}
无警告,控制台按预期记录结果。
[Core.Product(name: "shoe", price: 100.0), Core.Product(name: "t-shirt", price: 30.0)]
等等,但是我有很多依赖关系,有些相互联系,我该如何处理它们?
有了更多的模块和依赖项,接下来的问题显然是如何管理它们。让我们来看一些依赖管理器。
依赖经理
为了处理越来越多的依赖关系,我们需要一些方法来对它们进行分组和管理。
让我们从没有依赖项管理器的方法开始幼稚,所有代码在同一项目下的一个仓库中。
嵌入式应用
如果它非常适合小型应用程序,那么如果您拥有一个或两个以上的模块,它很快就会变得令人头疼。文件夹将无助于分隔。
进一步采用这种方法,下一步将是在一个工作空间中分离项目。这就是上面演示的解决方案。这是隔离代码并了解代码的可见性和责任的好方法。
模块应用
但是,它仍然在同一个git repo下。当项目要扩展时,回购可能会变得很拥挤。还要考虑构建时间:每个依赖项都是使用主应用程序重建的。
让我们尝试分离git repo并使用git子模块。已经更好了,代码可以在其他项目中重用,但是我们仍然受到构建时间的限制。
处理依赖关系的另一个角度是创建一个伞形框架,以将每个依赖关系嵌入到一个程序包中,以限制构建并保持整洁的工作空间。 事实是,如果您使用CocoaPods,您可能已经做到了。
如果您查看工作空间并探索Pods项目,它就是处理依赖项的方式。但是,构建时间仍然是瓶颈。
最后,另一个流行的依赖性管理器是Carthage。主要区别在于依赖项是在导入之前构建的。这是保持优化构建的最佳解决方案。
我没有提到Swift Package Manager(或SPM),因为到目前为止它仅可用于macOS。
它们也是Buck或Bazel等其他用于增量构建的新兴解决方案,但这首先要针对连续集成管道。
总之,我们了解了如何将代码隔离到模块中,使其在保持整洁的项目的同时易于重用和测试。可以在此处找到带有模块的示例项目。
推荐👇:
面试题持续整理更新中,如果你想一起进阶,不妨添加一下交流群1012951431
面试题资料或者相关学习资料都在群文件中 进群即可下载!