我使用的是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.

其他回答

事实证明罗伯·纳皮尔是对的。这是一个文件(实际上是一个方法),导致编译器去berzek。

别误会我的意思。Swift每次都会重新编译你所有的文件,但现在最棒的事情是,苹果在它编译的文件上添加了实时编译反馈,所以Xcode 6 GM现在可以实时显示哪些Swift文件正在编译以及编译状态,如下图所示:

因此,这是非常方便的,以了解您的文件花费这么长时间。在我的例子中,它是这段代码:

var dic = super.json().mutableCopy() as NSMutableDictionary
dic.addEntriesFromDictionary([
        "url" : self.url?.absoluteString ?? "",
        "title" : self.title ?? ""
        ])

return dic.copy() as NSDictionary

因为属性标题类型是var title:String?而不是NSString。当把它添加到NSMutableDictionary时,编译器要疯了。

改为:

var dic = super.json().mutableCopy() as NSMutableDictionary
dic.addEntriesFromDictionary([
        "url" : self.url?.absoluteString ?? "",
        "title" : NSString(string: self.title ?? "")
        ])

return dic.copy() as NSDictionary

使编译从10/15秒(甚至更多)下降到一秒…很神奇的。

对于调试和测试,请确保使用以下设置将编译时间从20分钟左右缩短到2分钟以内,

在项目构建设置中,搜索“优化” 将调试调到“最快[-O3]”或以上。 为活动体系结构设置构建:是 调试信息格式:DWARF 全模块优化:NO

我浪费了无数的时间等待项目的构建,却意识到我必须做出一个小小的更改,并不得不等待整整30分钟来测试它。这些设置对我很有用。(我仍在尝试设置)

但是,确保你至少设置了“DWARF with dSYM”(如果你想监控你的应用程序),并将Build Active Architecture设置为“NO”,用于发布/存档以推送到iTunes Connect(我记得在这里也浪费了几个小时)。

也许我们无法修复Swift编译器,但我们可以修复的是我们的代码!

在Swift编译器中有一个隐藏的选项,它会打印出编译器编译每个函数所需的确切时间间隔:-Xfrontend -debug-time-function-bodies。它允许我们发现代码中的瓶颈,并显著改善编译时间。

在终端中简单运行如下命令并分析结果:

xcodebuild -workspace App.xcworkspace -scheme App clean build OTHER_SWIFT_FLAGS="-Xfrontend -debug-time-function-bodies" | grep [1-9].[0-9]ms | sort -nr > culprits.txt

Awesome Brian Irace写了一篇关于它的精彩文章,分析你的Swift编译时间。

我在Xcode 6.3.1中没有任何工作-当我添加了大约100个Swift文件随机挂在构建和/或索引时。我尝试过模块化的选择,但没有成功。

安装和使用Xcode 6.4 Beta对我来说很有效。

Swift数组和字典构造似乎是一个相当流行的原因(特别是对于有Ruby背景的人来说),也就是说,

var a = ["a": "b",
         "c": "d",
         "e": "f",
         "g": "h",
         "i": "j",
         "k": "l",
         "m": "n",
         "o": "p",
         "q": "r",
         "s": "t",
         "u": "v",
         "x": "z"]

将可能是这应该修复它的原因:

var a = NSMutableDictionary()
a["a"] = "b"
a["c"] = "d"
... and so on