通过将功能构建为框架来提高iOS团队的生产力

向现有的大型代码库中添加功能是许多工程师在其编码生涯中将面临的挑战。 如果iOS应用程序已经存在了几年以上,那么它可能已经吸引了许多开发人员为许多功能做出了贡献,从而使其成为了许多版本。 通常,结果可能是非常大的代码库,具有不同程度的模块化,较长的构建时间,而且代码不是很干净。

Scout24上的iOS应用处于不久前还处于这种状态,我想与大家分享我们如何对开发环境进行重大改进以及带来的好处。

问题

如果您曾经在一个大型项目中使用Swift进行开发,那么即使稍作改动,您可能对构建整个应用程序模块所花费的时间太熟悉了。 关于如何改善总体持续时间,有大量资源。

Swift具有许多出色的语言功能,但是这些功能是以更长的编译时间为代价的。 即使进行了少量更改,您也可能要等待几分钟才能看到结果。 这确实让人分心,效率很低! 在编码时,时间和精力是您最宝贵的资源。

如何解决

较长构建时间的答案很简单: 使编译器构建更少的代码! 听起来很合理,但是我们如何实现呢? 答案是通过使用iOS框架将我们的代码划分为更小,更离散的功能块。

在此示例中,我们将从主应用程序模块开始,并添加一个包含一些UI功能的框架,该功能构成了我们将集成到我们的应用程序中的功能。

这有什么好处?

这么小的示例可能看起来并不明显,但是以这种方式进行开发的好处是巨大的。 当您必须将功能内置到具有大量旧组件的大型应用程序中时,它们特别大。

通过将功能构建为高度独立于主应用程序模块的独立模块,您可以将更多精力放在要创建的功能上。 您会发现,您被迫以仅公开应用模块所需内容的方式来组织代码,该代码往往更加清晰和经过深思熟虑,并且不太可能发展成意大利面条式混乱,因为这样做更困难这样做。

与框架一样,构建作为框架的功能的一个基本步骤是创建一个“包装器应用程序”,就像我们在本教程中所做的那样,该程序将您创建的功能最小化地集成到一个微型应用程序中。 该应用程序无需构建主应用程序模块所需的所有其他依赖项,因此构建时间将很快缩短。

创建一个新的应用程序工作区

您将需要为您的应用程序和功能所在的框架创建一个工作区。 首先单击Xco​​de中的File-> New- > Workspace 。 在要保存工作空间的位置创建一个新文件夹。

保存后,我们现在有了一个空白工作区。 现在,单击Xco​​de中的File-> New- > Project ,然后选择“ single view app”。

将项目命名为“ SimpleCounterApp”,并确保选择“ Swift”作为应用程序语言。 之所以这样命名,是因为它将仅包含应用程序模块。

在下一步中,选择保存SimpleCounter.xcworkspace的文件夹。 在“ 添加到”下,选择SimpleCounter工作区。 必须在Xcode中打开SimpleCounter.xcworkspace才能显示此选项。

创建项目并注意,现在我们有了一个看起来很无聊的项目。

让我们开始做一个框架! 我们将在以后的步骤中将功能集成到主应用程序中,因此现在无需执行任何操作。

再次单击文件->新建->项目 ,这一次,选择“ Cocoa Touch Framework”作为模板。

将框架命名为SimpleCounterFeature ,然后单击下一步。 在下一个屏幕上,选择保存.xcworkspace文件的文件夹,以使框架和应用程序位于同一根目录中。 然后,在“添加到”下 ,再次选择SimpleCounter工作区。 在“ 组”下,选择根工作区节点。

这会将框架添加到工作区,而不是应用程序模块。 保存项目。 您现在应该拥有一个看起来像这样的工作区:

在方案列表中,您还应该有两种方案,一种用于框架,一种用于应用程序。

由于此框架模板完全是准系统,因此它没有任何链接的依赖项。 因此,我们需要从UIKit开始添加基础知识。

导航到框架的项目设置,然后选择“ 构建阶段” 。 在“将二进制文件与库链接”下,单击“ +”按钮并链接UIKit和Foundation框架。 您的构建阶段屏幕应如下所示:

现在,让我们向框架添加一个带有笔尖的简单视图控制器。 单击文件->新建->文件,然后选择“快速文件”。 点击“下一步”。

将文件命名为CounterViewController并将文件添加到组SimpleCounterFeature。 默认情况下不会选择。

现在,您有了一个文件,该文件是SimpleCounterFeature框架目标的一部分。 使用nib文件(“新建文件”对话框中的“查看”模板)再次执行相同的操作,并确保将其添加到SimpleCounterFeature组。

从框架公开功能

在编写要从框架公开给应用程序模块的代码时,请务必牢记为接口提供的访问级别。 在为应用程序模块编写Swift代码时,我们通常并不真正关心公共开放内部访问级别。 这是因为所有代码都位于同一个模块中,因此区别不那么重要。 在模块中, 内部是成员属性和方法的默认访问级别,这意味着默认情况下它们在整个模块中都可用。

在开发框架时,情况有所不同。 由于您编写的代码将被打包到单独的二进制文件中,以供模块在其范围之外使用,因此访问级别更为相关。

如果要将任何内容暴露给外部,无论是结构,协议,类还是任何属性或方法,都需要指定公共访问级别。 否则,导入实体的模块将看不到该实体。 Swift文档对访问控制有很好的解释,完成本教程后,您可能会有所不同。

例如,在我们的CounterViewController类中,如果我们希望能够在框架模块之外使用它,则需要将该类公开。

成员IBOutlet属性在模块外部不可见,因为它们被标记为内部。

我不会详细介绍如何将笔尖连接到视图控制器,或者如何添加其余的计数器功能,因为这里没有什么特别的。 如果您有兴趣,可以签出示例项目以查看完成情况。 在界面生成器中,我只是创建了一个按钮和一个标签,并将它们连接到IBOutlets并添加了一些简单的功能。

将框架添加到应用程序模块

现在转到该应用程序模块的项目设置的“ 常规”部分。 在“ 嵌入式二进制文件”下 ,单击+按钮,然后添加SimpleCounterFeature.framework。

这会将框架添加到app模块的Embedded Binaries中并进行链接。 需要将框架添加到Embedded Binaries中,因为您的SimpleCounterFeature框架无法像UIKit一样适用于iOS,这意味着需要在构建期间将其复制到应用程序包中。

现在构建SimpleCounterApp方案。 如果构建成功,就可以开始集成框架了!

将框架集成到您的代码中

在将视图控制器集成到您的应用程序模块之前,我们需要先进行一些清理。 首先删除Main.storyboard文件,然后删除应用程序模块项目页面的“ 常规”选项卡中的“ 主界面”条目。

您也可以在主应用程序模块中删除ViewController.swift文件。 您将不会使用它。

AppDelegate.swift文件中,导入SimpleCounterFeature框架并使用根视图控制器作为CounterViewController创建一个UIWindow

现在,构建您的应用程序。 它应该成功构建并以CounterViewController为根启动。 你完成了!

想做更多吗?

我们遗漏了开发人员几乎始终在其代码库中需要的东西:第三方依赖性。 我写了一篇关于如何将它们集成到您的框架中的教程,并在下一篇文章中提供了一个更复杂的代码示例。

更多资源

  • 示例代码:https://github.com/akfreas/SimpleCounter
  • 关于访问控制的Apple文档:https://docs.swift.org/swift-book/LanguageGuide/AccessControl.html
  • 如何在内部iOS框架中使用CocoaPods:https://medium.com/@akfreas/how-to-use-cocoapods-with-your-internal-ios-frameworks-192aa472f64b

谢谢阅读!

如果您有任何疑问,意见或对以后文章的要求,请在下面发表评论!