vlambda博客
学习文章列表

Swift 项目编译优化(一)



Swift 项目编译优化(一)

前言
前段时间笔者组内同事十分快速地开发了一个应用(不妨设应用名为QiShareDemo),笔者在使用8+128的Mac Air 运行项目的时候,发现项目编译时间比较久,查看了相关资料,并做了部分实践,落地了这篇文章。笔者在 clone 了 QiShareDemo 后,发现全量编译编译项目的编译时间为105.207s;后来经过笔者的部分优化编译时间处理后,全量编译项目的时间缩短为44.573s;当然这里还可以继续做优化,可以根据项目中具体的代码的编译耗时排序,处理那些编译耗时较长的代码。

一、名词简介

下边笔者对本文中提到的名词做一个简单介绍。

1. 全量编译

以Xcode编译过程为例,笔者理解的全量编译的一种情况为:把Xcode 编译项目时生成的Derived Data 删除后,再次编译项目的过程。

2. 增量编译

以Xcode编译过程为例,笔者理解的增量编译的一种情况为:Xcode 已编译过项目的情况下,我们又修改了部分文件,那么编译的时候,就会编译我们修改过的文件,及引用过相关文件的文件。

3. Swift Compiler

如果项目不是 Objective-C 和 Swift 混编的项目而是纯 Swift 项目,那么编译过程用的是 Swift Compiler,笔者在下文中第三部分的2.1.2部分有提到详情。关于编译的更多详情可以查看 浅谈编译过程

二、Swift 项目的编译过程

使用 Xcode 查看项目具体编译过程的方式如下:

1. 用 Xcode 查看项目具体编译过程

用 Xcode 查看项目编译过程方式:command + b 编译项目,在 Xcode 中,按下图方式查看具体编译过程。

Swift 项目编译优化(一)
compileProcess1

笔者根据 Xcode 编译项目过程,做了如下 Swift 项目编译过程示意图。

Swift 项目编译优化(一)
SwiftCompileProcess.png

2. 查看项目编译时间

我们的目的是要优化项目的编译时间,那么首先我们应该知道当前编译时间。查看项目编译时间的方式为:在终端中输入如下命令:defaults write com.apple.dt.Xcode ShowBuildOperationDuration YES 之后在 Xcode 顶部的 切换Scheme和运行设备的那一栏中即可看到具体编译时间。查看具体编译时间方式如下图所示:

Swift 项目编译优化(一)
Xcode compile Time

上图是查看项目总体编译时间的方式,那么我们想要对项目做编译时间优化,就要找出来编译耗时长的部分。上文中提到了通过 Xcode 查看项目具体编译时间的方式,笔者也放了如下部分示意图。

Swift 项目编译优化(一)
compileProcess detail

三、减少项目编译时间的考虑

1. 调整 Xcode 的Build Settings 中的配置

关于调整 Xcode 的 Build Settings 中的配置,笔者查询资料后发现在 Xcode10 及之前调整空间比较大,在 Xcode11 的时候,笔者初步尝试后,发现调整 Xcode 的 Build Settings 中的配置对于优化项目编译时间影响不大。

2. 把稳定三方打包成 Framework

笔者在分析了项目编译时间后,发现 QiShareDemo 中引入的每个三方都各自花费了20s+的时间,记不清是查看了网上的文章示例还是如何,想到了如果在使用这些三方的过程中,不会频繁改动这些三方源代码的情况下,可以把这些三方打包成 Framework,尝试解决编译耗时久的问题。经过尝试把项目中的三方打成 Framework,供 QiShareDemo 使用后,就得到了一个明显的减少编译耗时的成效。从开始的笔者在 clone 了 QiShareDemo 后,全量编译编译项目的编译时间为105.207s;后来经过笔者初步把三方打包成 Framework 后,全量编译项目的时间缩短为44.573s;

2.1 浅谈编译耗时缩短的原因
2.1.1 把稳定三方打成 Framework 对编译影响

可以结合上一篇文章 浅谈编译过程来谈这个问题。关于项目直接使用 Framework ,会减少编译时间的原因,组内同学 沐灵洛 和 奇舞647 都提及过,笔者推测原因是:从编译过程来看,项目直接使用 Framework 相比使用 Cocoapods 的源代码依赖,就省了预编译、词法分析、语法分析、生成中间代码、生成目标文件的过程。所以就减少了编译时间。(编译过程更多信息可查看 浅谈编译过程) 这部分还有一个劣势,组内同学 大成小栈 提到说,打成Framework 后在调试修改源代码的时候就不方便了。这个是必然的,所以最好是把那些稳定的三方打包成 Framework ,或者是和组内同学分工合作,分别负责某个三方。

2.1.2 Objective-C 和 Swift 混编耗时影响

组内同学 沐灵洛 还结合着笔者发出的编译过程图,提及过Swift 和 OC 项目混编相对于纯 Swift 项目可能耗时更多的问题。这部分笔者的推测是看 Swift 项目的编译过程。如果只是单纯的 Swift 项目,编译的前端过程用 Swift 编译器就够用了。如果是Swift 和 OC 混编的项目,编译的前端过程还会用到 Clang ,Clang 会把 C、Objective-C 的 API 向Swift API 做一个对应。我想这个过程多少会比 Swift 编译器单纯编译Swift 代码多一些编译耗时的增加。下边笔者放了一个Swift Compiler 架构图,笔者是以流程图的方式绘制制作的Swift Compiler 架构图。

Swift 项目编译优化(一)
SwiftCompilerArchitecture.png

注:在之前的文章 浅谈编译过程中笔者介绍了 GCC、LLVM编译器,Swift 语言的编译器是用的自有的Swift Compiler。

3. 使用工具查看项目中代码编译耗时

可以使用工具 BuildTimeAnalyzer-for-Xcode查看项目中自己写的代码的编译时间。笔者使用 BuildTimeAnalyzer-for-Xcode 查看了项目编译时间,找出了2处编译时间耗时的地方。下图是笔者使用 BuildTimeAnalyzer-for-Xcode 查看出的项目编译时间耗时情况。笔者在Target -> Build Settings -> Swift Compiler 的 Other Swift Flags 中添加了如下配置:

-Xfrontend -warn-long-function-bodies=100-Xfrontend -warn-long-expression-type-checking=100-Xfrontend -debug-time-function-bodies

上述配置内容用于添加使用 BuildTimeAnalyzer-for-Xcode 的配置,用于查看出方法或表达式编译耗时超过100ms的位置以警告的形式表现出来。

下边笔者举2个遇到的编译耗时的代码示例。

3.1 ??(nil-coalescing 空合并运算符) 及 ”+“拼接在一起的耗时

这种 “??” 和 “+”拼接字符串用在一起时,在编译过程中会比较耗时。最好改成短短的小代码语句。

Swift 项目编译优化(一)
compileTime1

经过笔者把上述耗时代码使用 if let 的方式处理后,编译耗时的问题已得到了解决。

Swift 项目编译优化(一)
compileTime2
3.2 使用 snapkit 时候可能遇到的编译耗时

笔者打开了测出的使用 Snapkit 的过程中,可能遇到的编译耗时的代码。检测编译耗时的示意图如下:

Swift 项目编译优化(一)
compileTime3

如果把上述的红色箭头指向的代码改成使用蓝色箭头指向的代码可以解决编译耗时的问题。笔者收获是:使用Snapkit 布局的时候,参考值尽可能是一个明确值,尽可能不要设置参考的时候,再让编译器去帮我们计算值,我们可以尽可能多的告诉编译器我们知道的事情。

四、其他考虑方向

1. SwiftUI

使用SwiftUI可以实时查看代码显示效果,并可以在不同设备上预览效果。使用 SwiftUI 可以提高开发效率。SwiftUI 官方教程:Learn to Make Apps with SwiftUI

2. Swift的HotReload尝试

五、参考学习网址

  • Swift Compiler
  • Incremental Compilation
  • Optimizing Build Times in Swift 4
  • [贝聊科技]如何将 iOS 项目的编译速度提高5倍
  • 提升大量的编译速度!Coupang App 工程提效实践
  • 如何将 iOS 工程打包速度提升十倍以上

Swift 项目编译优化(一)
image

推荐文章:
Swift 5.1 (14) - 初始化和反初始化
Swift 5.1 (15) - 可选链接
浅谈编译过程
深入理解HTTPS
浅谈 GPU 及 “App渲染流程”
iOS 查看及导出项目运行日志
Flutter Platform Channel 使用与源码分析
开发没切图怎么办?矢量图标(iconFont)上手指南
DarkMode、WKWebView、苹果登录是否必须适配?
奇舞团安卓团队——aTaller
奇舞周刊


Swift 项目编译优化(一)

更多精彩内容,尽在阅读原文