我使用的是Xcode 6 Beta 6。

这个问题已经困扰我一段时间了,但现在已经到了几乎无法使用的地步。

我的项目开始有一个相当大的65个Swift文件和一些桥接Objective-C文件(这真的不是问题的原因)。

似乎对任何Swift文件的任何轻微修改(比如在应用程序中几乎不使用的类中添加一个简单的空白)都会导致指定目标的整个Swift文件被重新编译。

经过深入的调查,我发现几乎100%的编译器时间是CompileSwift阶段,Xcode在目标的所有Swift文件上运行swiftc命令。

我做了一些进一步的调查,如果我只保持应用程序委托与默认控制器的编译是非常快的,但随着我添加越来越多的项目文件,编译时间开始变得非常慢。

现在只有65个源文件,每次编译大约需要8/10秒。一点也不快。

除了这篇文章,我还没有看到任何关于这个问题的文章,但这是一个旧版本的Xcode 6。所以我在想是不是只有我一个人有这种情况。

更新

我在GitHub上检查了一些Swift项目,比如Alamofire、Euler和CryptoSwift,但没有一个项目有足够的Swift文件来进行真正的比较。我发现唯一一个开始有一个像样的大小的项目是SwiftHN,即使它只有12个源文件,我仍然能够验证同样的事情,一个简单的空间和整个项目需要重新编译,这开始需要一点时间(2/3秒)。

与分析和编译都非常快的Objective-C代码相比,Swift真的感觉永远无法处理大项目,但请告诉我我错了。

更新与Xcode 6 Beta 7

仍然没有任何改善。这开始变得荒谬了。由于Swift中缺少#import,我真的不知道苹果将如何优化这一点。

更新Xcode 6.3和Swift 1.2

苹果增加了增量构建(以及许多其他编译器优化)。你必须将你的代码迁移到Swift 1.2才能看到这些好处,但苹果在Xcode 6.3中添加了一个工具来帮助你做到这一点:

然而

不要像我一样高兴得太快。他们用于增量构建的图形求解器还没有很好地优化。

事实上,首先,它不会查看函数签名的变化,所以如果你在一个方法的块中添加一个空格,所有依赖于这个类的文件都将被重新编译。

其次,它似乎基于重新编译的文件创建树,即使更改不影响它们。例如,如果将这三个类移动到不同的文件中

class FileA: NSObject {
    var foo:String?
}
class FileB: NSObject {
    var bar:FileA?
}
class FileC: NSObject {
    var baz:FileB?
}

现在,如果您修改了FileA,编译器显然会将FileA标记为要重新编译。它还会重新编译FileB(基于对FileA的更改,这是可以的),但也会重新编译FileC,因为FileB是重新编译的,这非常糟糕,因为FileC在这里从不使用FileA。

所以我希望他们能改进依赖树求解器…我用这个示例代码打开了一个雷达。

更新与Xcode 7 beta 5和Swift 2.0

昨天苹果发布了beta 5,在发布说明中我们可以看到:

Swift语言和编译器 增量构建:仅改变函数体将不再导致依赖文件被重建。(15352929)

我已经试过了,我必须说它现在真的(真的!)很好。他们极大地优化了swift中的增量构建。

我强烈建议你创建一个swift2.0分支,并使用XCode 7 beta 5保持你的代码是最新的。你会对编译器的增强感到满意(但是我想说XCode 7的全局状态仍然很慢并且有bug)

用Xcode 8.2更新

距离我上次更新这个问题已经有一段时间了,所以就在这里。

我们的应用程序现在大约有2万行几乎全是Swift代码,这还不错,但并不突出。它经历了迅速的迁移。在2014年年中的Macbook pro (2.5 GHz英特尔酷睿i7)上编译大约需要5/6m,这在一个干净的构建上是可以接受的。

然而,增量构建仍然是一个笑话,尽管苹果声称:

Xcode不会在发生小变化时重新构建整个目标。(28892475)

显然,我认为我们中的许多人在检查完这些废话后只是笑了(添加一个私有(私有!)属性到我的项目的任何文件将重新编译整个东西…)

我想让你们看看苹果开发者论坛上的这个帖子,上面有关于这个问题的更多信息(也感谢苹果开发者偶尔就这个问题进行的交流)。

基本上,人们已经提出了一些改进增量构建的方法:

添加一个HEADER_MAP_USES_VFS项目设置为true 禁用从您的方案中查找隐式依赖项 创建一个新项目,并将文件层次结构移动到新项目。

我试试3,但是1/2行不通。

在整个情况中具有讽刺意味的是,看看关于这个问题的第一篇文章,当我们第一次编译时,我们使用的是Xcode 6和swift 1或swift 1.1代码,而现在大约两年后,尽管苹果进行了实际的改进,情况还是和Xcode 6一样糟糕。多么讽刺。

我真的很后悔在我们的项目中选择了Swift而不是Obj/C,因为它涉及到日常的挫折。(我甚至切换到AppCode,但这是另一个故事)

不管怎样,我看到这篇SO帖子有32k+的阅读量和143个上升量,所以我想我不是唯一一个。坚持住,伙计们,尽管对这种情况感到悲观,隧道尽头可能会有一线光明。

如果你有时间(和勇气!)我猜苹果欢迎雷达的关注。

更新Xcode 9

今天偶然发现的。Xcode悄悄地引入了一个新的构建系统来改善当前糟糕的性能。您必须通过工作空间设置启用它。

已经尝试过了,但会在完成后更新这篇文章。不过看起来很有希望。


当前回答

不幸的是,Swift编译器仍然没有针对快速和增量编译进行优化(截至Xcode 6.3 beta)。同时,你可以使用下面的一些技巧来提高Swift的编译时间:

Split the app into Frameworks to reduce recompilation impact. But be aware that you must avoid cyclic dependencies in your app. For futher info on this topic check this post: http://bits.citrusbyte.com/improving-swift-compile-time/ Use Swift for parts of your project that are quite stable and don't change often. For other areas where you need to change very often or areas that require lot of compile/run iterations to be complete (almost any UI related stuff), better use Objective-C with a mix-and-match approach. Try runtime code injection with 'Injection for Xcode' Use roopc method: http://roopc.net/posts/2014/speeding-up-swift-builds/ Relief the swift type inference engine by giving some hints with explicit casts.

其他回答

对于混合Objective-C和Swift代码的项目,我们可以在Other Swift Flags中设置-enable-bridging-pch。这样,桥接头只被解析一次,结果(一个临时的“预编译头”或“PCH”文件)被缓存并在目标中的所有Swift文件中重用。苹果公司声称,它可以将构建时间缩短30%。参考链接:

注意:这只适用于Swift 3.1及以上版本。

不幸的是,Swift编译器仍然没有针对快速和增量编译进行优化(截至Xcode 6.3 beta)。同时,你可以使用下面的一些技巧来提高Swift的编译时间:

Split the app into Frameworks to reduce recompilation impact. But be aware that you must avoid cyclic dependencies in your app. For futher info on this topic check this post: http://bits.citrusbyte.com/improving-swift-compile-time/ Use Swift for parts of your project that are quite stable and don't change often. For other areas where you need to change very often or areas that require lot of compile/run iterations to be complete (almost any UI related stuff), better use Objective-C with a mix-and-match approach. Try runtime code injection with 'Injection for Xcode' Use roopc method: http://roopc.net/posts/2014/speeding-up-swift-builds/ Relief the swift type inference engine by giving some hints with explicit casts.

重新启动我的Mac对这个问题有奇效。通过重新启动,我从15分钟构建到30秒构建。

因为所有这些东西都是测试版,而且Swift编译器(至少到今天为止)还没有打开,我猜你的问题没有真正的答案。

首先,比较Objective-C和Swift编译器有点残酷。Swift仍处于测试阶段,我相信苹果正在努力提供功能和修复错误,而不仅仅是提供闪电般的速度(你不会从购买家具开始盖房子)。我猜苹果会在适当的时候优化编译器。

如果出于某种原因,所有源文件都必须完整编译,那么可以选择创建独立的模块/库。但是这个选项还不可行,因为Swift在语言稳定之前不允许使用库。

我猜他们会优化编译器。由于同样的原因,我们不能创建预编译模块,很可能编译器需要从头编译所有内容。但是一旦语言达到稳定的版本,二进制文件的格式不再改变,我们将能够创建我们的库,也许(?)编译器也将能够优化它的工作。

不过,这只是猜测,因为只有苹果知道……

这可能与项目的规模无关。它可能是一段特定的代码,甚至可能只有一行。您可以通过尝试一次编译一个文件而不是整个项目来测试这一点。或者试着查看构建日志,看看哪个文件花了这么长时间。

这段38行的要点代码在beta7中要花一分钟多的时间来编译,这是可能导致麻烦的代码的一个例子。所有这些都是由这一个块引起的:

let pipeResult =
seq |> filter~~ { $0 % 2 == 0 }
  |> sorted~~ { $1 < $0 }
  |> map~~ { $0.description }
  |> joinedWithCommas

只需将其简化一两行,它几乎可以立即编译。问题是这会导致编译器中的指数增长(可能是阶乘增长)。显然,这并不理想,如果你可以隔离这种情况,你应该打开雷达来帮助清理这些问题。