作者 | Saru 
来源 | Medium

如果你正在寻求提高 Xcode 构建性能的方法,那你找对地方了。我看过很多博客或文章,很少能详尽说明如何加快 Xcode 构建速度,所以我决定整理一篇。

减少构建时间对于开发人员来说非常有意义,尤其是构建那种有大量依赖库的主传代码时。在本文中,我将尝试列出所有可能的方法,这些方法可以用来调整 iOS 项目以提高 Xcode 构建的性能。

这里先做一些必要的简要说明:

• Action Points - 可以在 Xcode 中执行的特定动作

• Real-time Effect - 我选择的一个非常棒的开源库 SwiftBlog,在此基础上进行优化,并实时查看效果。

事不宜迟,让我们开始吧。

显示构建时间

首先,我们需要知道 Xcode 花了多少时间来构建我们的项目。默认情况下,Xcode 并不会显示构建时间,因此我们必须启用这项功能。

Action Points

1、在终端运行以下命令

defaults write com.apple.dt.Xcode ShowBuildOperationDuration -bool YES

2、现在,在构建项目时,就会在 Xcode 的构建条中显示构建时间了。

注意点 1:如果 Xcode 由于某种原因未显示,那么尝试重新启动 Xcode

注意点 2:为了显示正确的构建时间,先确保深度清理项目,也就是说需要清除 Build 文件夹(Command + Shift + K)的所有数据。

能够获取构建时间后,我们就可以来实际调整设置,以提高构建过程的性能了。

构建系统

Xcode 9 在其预览版中引入了一个新的构建系统。而到了 Xcode 10,新的构建系统则成了默认设置。这个新的构建系统的主要目标就是要减少总体的构建时间。

Action Points

要使用新的构建系统,可以在 File -> Workspace/Project Settings 中启用它。

为了了解其实际效果,我们可以尝试使用新旧两种构建系统分别来构建项目,以对比两者的构建时间。虽然在我们的示例项目中,两者差别不是很明显,但在重型项目中会有明显的区别。如果有条件,可以在那些有大量依赖关系老项目中试一试。

Reat-time Effect

现在,让我们基于 SwiftBlog,来使用两种构建系统对其进行构建。

看到差别了吗?0.991秒(旧版为4.223秒,新系统为3.232秒)。这个实例并没有任何相依,但仍然相差约1秒,效果还是很显著的。

当然,这只是 Xcode 本身的默认优化。接下来,我们来看看可以通过调整哪些项目设置来减少构建时间。

架构影响

在开发过程中,我们更关注构建时间,这实际上会占用我们的大部分时间。当以调试模式来构建项目时,最好只针对特定的架构来构建。虽然这是 Xcode 的默认选项,但以防万一,最好先确认一下。

设备和模拟器有不同的架构,但通常在开发过程中,我们希望 Xcode 或者在设备或者在模拟器上运行。所以,设置 Build Active Architecture Only 为 Yes ,来要求编译器仅生成一种架构的二进制文件。

Action Points

在项目的 Build Settings -> Build Active Architecture Only 中,将 Debug 设置为 Yes ,将 Release 设置为 No 。

让我们在 SwiftBlog 上将 Debug 设为不同的值,看看效果。

可以看到两者相差 3.385s。

注意,我们在这里使用的是旧版构建系统,如果使用新的构建系统,同样会有巨大差异。

编译模式

Compilation Mode 告诉编译器是构建项目中所有文件还是仅构建修改后的文件。 Incremental (增量)表示仅编译已修改的文件, Whole Module 表示不考虑修改而构建项目中所有文件。

1、进行 Build Settings -> Compilation Mode 。默认情况下,Xcode 10+ 是将其设置为 Incremental(Debug) 和 Whole Module(Release) 。

2、如果项目中的构建设置和上面相同,那么是 OK 的,否则,修改你的设置。

现在,让我们在 SwiftBlog 项目中配置该荐为不同设置,来看看实际效果。

注意:需要通过以下步骤来看看这项优化:

1、构建一次项目

2、做一些修改

3、再次构建项目,这时就能看到 Compilation Mode 的效果了。

在这个实例中,你可能会发现和预期不一样。确实,在 SwiftBlog 这个小项目中,最好还是选择 Whole Module ,因为编译器会省略检测更改文件的过程,因此反而能节省一些时间。但是在有很多依赖的项目中, Incremental 无疑是最佳选择。

优化级别

Optimization Level 告诉编译器将构建优化到某个级别。通常,Debug 的构建设置为 No Optimization ,这样可以调试通过 let/var 包含的值。这在调试阶段是非常有必要的。

1、进入 Build Settings -> Optimization Level ,然后查看设置的值

2、如果不进行大量调度,最好将其设置为 Optimize for Speed ,由于编译器将省略将值附加到调试器线程的步骤,因此将减少构建时间。

注意:还有另一个设置,即 Optimize for Size ,通常是指机器代码生成的整体大小,而不是应用程序的大小。鉴于此,我们主要关注减少本文讨论的“构建时间”,因此忽略这一项。

让我们将些配置应用于 SwiftBlog 项目。

注意:应该按照 Compilation Mode 中提到的相同步骤来操作,以查看效果

这里只有 0.2s 的微小差异,但是它将对大型项目产生重大影响。

依赖管理

iOS有2个主要的依赖管理器:Carthage和Cocoapods。

两者都有各自的优点和缺点。关于孰优孰劣,已经有很多争论了,不过本文不会对些深入探讨。我们来看看它们与构建过程的关系。

通常,在大多数项目中,一旦集成了依赖库 lib/module/framework,我们就希望不更改这些库的源码。即使要修改,将这些修改集中在独立的 repo/module/framework 中,然后将特定 module/framework 集成到项目中,始终是一种最佳实践。基本思想是在模块下的情况下,尽可能地分离 module/framework。

静态/动态 framework 在将任何第三方库集成到我们的 iOS 项目中时非常有用,因为一旦生成 framework,就不会在项目中重新编译。这可以节省大量时间,因此,这也是一些人选择 Carthage,而不是 Cocoapods 的原因之一。

当使用 Cocoapods 来管理依赖项时,每次编译工程,所有的依赖项都会被编译。而如果使用 Carthage,在添加依赖项时,依赖库只被编译一次。它会生成一个 framework,并链接到工程,在构建工程时,不会再去编译依赖项。

我们将看看如何让编译器并行执行构建,该构建与项目中定义的依赖关系紧密相关。

1. 构建的机器内核数

先决条件—查看Mac的内核数量

1、在终端运行以下命令:

sysctl -n hw.ncpu

2、它会输出一个整数,表示计算机的内核数:

4 // 这是我的内核数

有 12 个内核的 iMac 这样的机器运行相同构建的速度比我的快 3 倍。因此,计算机的内核数起着很大的作用,它与构建执行时间成正比。

默认情况下,Xcode 使用与计算机 CPU 内核数相同的线程数。但是,调整线程数,使用更多的线程,可以显著减少构建时间(在某些情况下可以减少 30%)。这个过程利用了处理器处理多线程或模拟额外内核的能力。需要注意的是,你需要通过尝试来确定代码并行构建的收益情况,然后相应地调整线程数。

修改线程数

让我们尝试修改线程数。从终端运行以下命令:

默认写入com.apple.Xcode PBXNumberOfParallelBuildSubtasks 8

接下来是使并行构建执行更简单的方法。这是通过Xcode UI本身完成的,后者会自动执行此优化。

2. 执行并行构建

我们将研究如何在Xcode中启用并行构建执行。

Action Points

导航到 Edit Scheme -> Build ,确保勾选 Parallelize Build 和 Find Implicit Dependencies 。

Build Hypothesis

Xcode 编译器获取项目的源代码,并构建一个树状结构来定义模块的依赖关系。然后采用自下而上的方法进行编译,即首先编译最小依赖性的模块。

通常,Xcode 项目会依赖于其它 framework 或 target。例如,当一个项目添加了 Target Dependencies 时,编译器首先要确保这边链接的目标 framework/module 先被编译。同时,在执行 test target 时,编译器首先确保 app target 被编译。因此,依赖关系在使编译器以最佳方式执行并行构建任务中起着重要的作用。在这里,我们可以做的是:

• 按执行顺序列出所有依赖项

• 按执行顺序列表项目中的所有 target

• 减少依赖

• 解耦或模块化代码库,以生成独立的模块

尽管依赖关系始终由编译器在内部进行标识,但最好将它们按照执行顺序放置。这最终可以帮助编译器在构建过程中,减少内部重新排序依赖的时间。

正确处理完后,这将让构建性能提高 2 ~ 3 倍,当然这取决于项目的复杂性。

Real-time Effect

对于没有或很少依赖项的小型业余项目来说,结果可能适得其反,即并行构建实际上会增加构建时间。我们可以在 SwiftBlog 项目上观察到这一点。

但是,对于有大量依赖关系的实际项目,最佳做法是使用并行构建。

关于依赖关系排序的另一个重要特征是链接框架,我们下面来讨论。

链接框架

Link Frameworks Automatically 表示添加到项目中的任何 framework 都应自动链接并由编译器在构建过程中考虑使用。

Xcode 默认将 Link Frameworks Automatically 设置为 Yes 。

但是,苹果并不保证这一点,而是希望开发人员将任何外部 framework 链接到 Build Phases -> Link Binary -> With Libraries 或 Target Dependencies 。我们不必对 UIKit 、 Foundation 这些隐式依赖项执行此步骤。

因此,这里的总体目标是对于外部 framework 不要过多依赖 Link Frameworks Automatically。最好在构建阶段中手动链接依赖项。

识别耗时的代码

Xcode 允许我们识别导致编译时间严重滞后的代码块。你可以为代码块执行指定一个时间限制,交让 Xcode 对超出指定时间限制的代码给出警告。

Action Points

1、导航到 Build Settings -> Other Swift Flag ,并添加以下标记:

-warn-long-function-bodies=200-warn-long-expression-type-checking=200

整数值 200 代表毫秒数。因此,在执行构建后,Xcode 将对任何执行时间超过 200 毫秒的函数或表达式给出警告。

2、添加这些标志后,无论何时构建项目,Xcode 都应该显示警告。

当你需要确定消耗比预期时间更多的那些函数或表达式时,这非常有用。

dSYM的影响

dSYM 文件对崩溃报告文件的去符号化过程非常有用。编译器需要一些时间来生成 dSYM 文件。仅当没有附加 Xcode 调试器时,启用它才有意义。因此,最好在模拟器上运行时将其禁用。

Action Points

1、导航到 Xcode 的 Build Settings -> Build Options

2、在 Debug Information Format 下,设置值 为 DWARF(Debug) 和 DWARF with dSYM File(Release)

这个设置告诉编译器在调试模式下省略创建 dSYM 文件的过程。这在一定程序上能节省构建时间。

Real-time Effect

让我们在 SwiftBlog 中配置一下

可以看到,两者相差 0.6s。

Objective-C/Swift 互操作性

随着 Swift 的到来,出现了混合开发,工具的一部分旧代码库已迁移到最新语言,而另一部分继续使用Objective-C。最终要求开发人员以某种方式处理互操作性。

为了实现互操作性,我们必须处理两种类型的头文件:

• Bridging Header -- 包含应公开给 Swift 的所有 Objective-C 接口

• Generated Header -- 包含所有应公开给 Objective-C 的 Swift 接口

这些头文件定义了两种语言编写的文件的依赖性。这两种语言的文件之间的互操作性是通过 Bridging/Generated Header 实现的。对头文件的更改将极大地影响构建时间。例如,Swift 接口文件中的微小变化会让编译器重新编译所有引用了该文件的Objective-C文件,反之亦然。

所以,最好只在两种语言的文件中同时公开所需的接口。通过添加访问修饰符:private/protected,避免添加/导入不必要的文件。

减少 UITests 执行时间

这听起来有些怪异,因为从技术上讲这没有意义,但确实如此。

在运行 UI 测试用例时,请尝试将模拟器的物理和像素窗口大小调整为尽可能最小。然后,可以看到 UITest 用例执行时间的一些改善。

发生这种情况是因为 Xcode 运行 UI 测试用例时,通常会在模拟器上安装并运行实际的应用程序以执行任何给定的UI测试用例。这意味着它实际上就是使用该应用程序的真实用户。因此,就像使用该应用程序的真实用户一样,在运行UI测试用例时,会消耗系统内核/资源。

因此,始终建议将模拟器设置降至最低,以减少对系统资源的使用。这最终将加快测试用例的执行速度,并减少总体执行时间。

结论

我们看到了许多选项设置,以提高 Xcode 构建性能。Xcode确实为我们提供了多种可配置选项的组合,但是由我们来确定哪种组合是最有效的并且最适合特定项目的。但是,只有通过尝试各种组合的选项才能发现这一点。

近期精彩内容推荐:  

 妹子 rm -rf 把公司整个数据库删没了...

 当互联网码农遇见国企老同学

 推荐33个IDEA最牛配置,写代码太爽了

 Python中zip()函数的解释和可视化

在看点这里好文分享给更多人↓↓

Xcode 构建优化全指南相关推荐

  1. 从DeepNet到HRNet,这有一份深度学习“人体姿势估计”全指南

    大数据文摘出品 来源:blog.nanonets 作者:栾红叶.熊琰.周家乐.钱天培 从DeepNet到HRNet,这有一份深度学习"人体姿势估计"全指南 几十年来,人体姿态估计( ...

  2. [原创]Java性能优化权威指南读书思维导图

    [原创]Java性能优化权威指南读书思维导图 书名:Java性能优化权威指南 原书名:Java performance 作者: (美)Charlie Hunt    Binu John 译者: 柳飞 ...

  3. 企业如何从 0 到 1 构建整套全链路追踪体系

    简介:本文将分享 ARMS 在全链路追踪领域的最佳实践,分享主要分为四部分.首先,是对分布式链路追踪的整体简介.其次,是对 ARMS 在分布式链路追踪领域的核心能力进行介绍.然后,介绍如何从 0 到 ...

  4. webpack那些事:浅入深出-源码解析构建优化

    基础知识回顾 入口(entry) module.exports = {entry: './path/to/my/entry/file.js' }; //或者 module.exports = {ent ...

  5. Android-App-启动优化全记录,这么香的技术还不快点学起来

    应用启动的一般流程 应用的启动,从桌面点击应用图标到主界面用户可操作,大致遵循下面的流程: 可以看到应用启动过程中,最重要的两个进程就是 SystemServer 和 App Process . 其职 ...

  6. 安卓工程师跳槽面试全指南

    课程介绍 年关将至,不少人出于职业规划的考虑,会开始出现跳槽的想法.跳槽念头一旦产生,所有的咨询都不过是为了"说服自己"而已.于是,我们要关注的重点就变成"怎么跳得更好? ...

  7. 基于Kubernetes支撑的项目,环境规划,构建优化,监控报警怎么做才好?

    前言 随着云计算技术的不断发展,容器和Kubernetes已经成为云原生应用的基石,容器的周边生态也日益成熟,微服务.服务网格.DevOps等技术相继涌现. 容器的出现,推动了软件开发.测试.部署.运 ...

  8. 详解webpack构建优化

    当项目越来越复杂时,会面临着构建速度慢和构建出来的文件体积大的问题.webapck构建优化对于大项目是必须要考虑的一件事,下面我们就从速度和体积两方面来探讨构建优化的策略. 分析工具 在优化之前,我们 ...

  9. Java应用云原生构建优化

    layout: post title: Java应用云原生构建优化 catalog: true tag: [云原生, Devops, K8s, Java] 1. 面临的问题 2. Jib调研 2.1. ...

最新文章

  1. c语言通过域组策略下发软件,windows 2008 server 域环境通过组策略下发计划任务(示例代码)...
  2. 创建型设计模式 之 单例模式
  3. CriminalIntent项目的开发
  4. ueditor html中使用方法,vue集成百度UEditor富文本编辑器使用教程
  5. 【计算机组成原理】字符、字符串以及汉字的表示方法
  6. C++ primer 第10章 泛型算法
  7. 【ES6(2015)】Reflect
  8. 【转】JS判断SWF,JPG加载完毕、兼容(Activex,plugIn)所有浏览器
  9. idea 导入maven项目
  10. Merry Christmas
  11. 【Missing separate debuginfos, use: debuginfo-install glibc-2.17-222.el7.x86_64】 解决方法
  12. vue插件颜色选择器
  13. PJSIP集成G729
  14. Canvas之绘制折线图
  15. 《金融科技(FinTech)发展规划(2019-2021年)》梳理
  16. 特斯拉Tesla Model 3整体架构解析
  17. labelme json转换为coco json 格式 包含area面积
  18. 如有问题,请及时联系 || 如有不足,请批评指出,一定会虚心改正 || 如有好的意见 ,欢迎下面留言
  19. annotation 的方法
  20. 翻过这座山之自定义mybatis框架

热门文章

  1. 小白福音——VBA编程常用——命令三百例
  2. 我的编程之路:「懒惰」是程序员最大的美德
  3. Redis 安装部署教程
  4. 《Python从入门到实践》第五章动手试一试
  5. puppy linux php,Puppy Linux(小巧实用操作系统)
  6. 2012年最新的12款超棒jQuery插件
  7. 你不得不关注的5 大Android 开发技术——2020
  8. EdgeBoard中“活灵活现”的算子
  9. 统一用户登录管理认证LDAP 服务端部署
  10. android 使用asm.jar将android手机屏幕投影到电脑上