53

After iPhone app that I'm writing in Swift become quite big (> 150 .swift files + various Objective-C libs), Xcode start behave pretty badly:

  • every second compilation I get various errors, e.g.:

    Command failed due to signal: Segmentation fault: 11

  • compilation take enormous amount of time (> 2 min on MacBook Pro Retina)
  • and so on.

I just wonder if everyone has same problems and maybe someone found a way to reduce this nightmare?

What I have done so far — I split project into several dynamic frameworks that I link from main project, it helps to reduce compile time, but introduce some new problems.

I also use iRamDisk to keep DerivedData folder in RAM and periodically delete all files from it, it sometimes helps with SourceKit crashes.

Tomasz Bąk
  • 6,124
  • 3
  • 34
  • 48
Alexey Globchastyy
  • 2,175
  • 1
  • 15
  • 19

6 Answers6

60

Swift toolchain is still a bit gross, you'll need to use some temporary workarounds until Apple fixes it (see UPDATES below)

Here is a list of items that you can do to keep yourself from going crazy.

Slowness caused by immature Swift compiler

  • Change your development workflow using Injection for Xcode. Once you installed the plugin, you'll be able to inject code changes in your simulator\device without recompiling. You don't need to hardcode\modify anything in your project. We started using it recently at work and it made a huge impact on our side, even if it doesn't apply to every use case (for example you can't create new functions, you can only modify the existing ones).

  • Some particular code constructs that the compiler doesn't like and takes too much time to compile. The most common problem is with the Type Checker that slows down compile time exponentially based on how many type checks it needs to do (read more here for practical examples and here for a detailed explanation). In order to identify if you are suffering from this problem you can follow this blog post, you will gather information about the functions that creates slowness by using some compiler additional flags. Alternatively you can use this Xcode plugin to identify the source of the build slowness.

  • Use dynamic frameworks wisely, where it makes sense. A framework recompilation will be done only when you modify one of its Swift files (dynamic frameworks are only available for iOS >= 7).

  • Condense code in the same files. Lowering the number of Swift files speeds up the compile process sensibly. You can easily achieve it enabling "Whole module optimization" by adding a user-defined custom flag SWIFT_WHOLE_MODULE_OPTIMIZATION and set it to YES and at the same time set optimization level to none (to disable optimizations that would make it slow) OUTDATED You may consider to use this gist, it's a build script that collapses all your code in a "merge.swift" file. You'll need to create a new target for it, but it is worth a try.

  • Double check things listed here (there are a few some more misc reasons because the compilation is slow)

  • OUTDATED Try the approach described in this blog post, it involves creating a build script that generates a make file. It requires manual intervention on the build script (it contains the list of swift files).

  • OUTDATED Try this hacked up incremental compilation technique

UPDATE: Incremental builds introduced on Swift 1.2 (Xcode 6.3)

Apple finally introduced incremental builds with Swift 1.2 (shipped with Xcode 6.3). It's not still perfect, but it's a huge improvement.

From now on a class is recompiled only when it is changed (or when one of the class it depends on has been changed). However the compiler still can’t understand if the changes to a class are to its interface or not. So any kind of change to a class causes a recompilation of that class and all of its dependencies.

UPDATE: Recompile dependent classes only when public interface changes introduced on Swift 2.1 (Xcode 7.1)

Starting from Swift 2.1 (Xcode 7.1), the dependent classes are recompiled only when you change the public interface of a class, and not at every change. This makes an huge difference in particular for big projects.

Project (mis)configuration (not related to Swift)

  • Be sure that "Build Active Architecture Only" is YES for debug.
  • Be sure that you didn't add pre\post compilation scripts that take too much time.
starball
  • 20,030
  • 7
  • 43
  • 238
Daniele
  • 2,461
  • 21
  • 16
  • Thanks for detailed answer — many good points, will definitely try it. – Alexey Globchastyy Jan 26 '15 at 08:29
  • 1
    You're welcome. In the answer I focused on how to speed up the compilation. However it's clear that in your case, you need to dig into your code to find the problem that causes the compiler segmentation fault. I don't think the segfault is related to the size of the project, are you able to reproduce it consistently? if so, you should try to isolate the problem (since you don't have clues, you could start deleting\commenting classes - I see how it can be hard, but can be a way). ps: what's the problem that you mentioned with frameworks? We use them really wisely and we don't have problems. – Daniele Jan 29 '15 at 19:27
  • Main problem for me with frameworks, I didn't figure out yet, what is the right way to add Objective-C lib (eg. FacebookSDK) to Swift Framework, there is no Bridging Header's inside Framework, as far as I understand – Alexey Globchastyy Feb 01 '15 at 17:15
  • You need to import every Objective-c header directly on the umbrella header of the swift dynamic framework. You can read more about frameworks in general here http://blog.cocoapods.org/Pod-Authors-Guide-to-CocoaPods-Frameworks/ Note that it's not a generic tutorial about frameworks, but it contains a lot of good information. When cocoapods will support dynamic framework, all of it should be automatically handled through dependencies of your framework, expressed on the Podfile – Daniele Feb 03 '15 at 19:08
  • 1
    Hey Alexey, it looks like Xcode 6.3 beta (swift 1.2) could solve the problem entirely, now we should finally use incremental builds, and it looks like they solved many compiler bugs, so take a try!. – Daniele Feb 09 '15 at 23:08
  • Nice post. One caveat - I think frameworks are not an option if want to support iOS 7 – Blago Feb 13 '15 at 16:39
2

Apple has some advices for speeding up your Xcode build in Technical Note 2190. Have you thought about creating and precompiling an own framework for outsourcing unchanged Swift modules or some/all Objective-C code?

Remove all type inferences in Swift.

This SO topic has some nice ideas and this blog post suggest to

  1. stop generating dSYM bundles and
  2. avoid compiling with -O4 if using Clang.

Although lots of these improvements are related to Objective-C, I am quite sure, that some of them are still relevant for Swift.

Michael Dorner
  • 17,587
  • 13
  • 87
  • 117
  • 3
    "I am quite sure, that some of them are still relevant for Swift." I'm not so sure. There is no such thing as precompilation for Swift, and the things that are slowing down Swift compilation are unique to Swift. Just to give a simple example, merely having a lot of string "addition" can bring compilation to its knees. – matt Jan 23 '15 at 00:07
  • 1
    Thanks for a comment. Didn't know about dSYM before, that's a good point. About frameworks - thats how I'm doing it now, there are some problems with this, because project is still in earlier stage, I don't have much code that don't need to be changed often. Now I try to restructure project in more modular way. – Alexey Globchastyy Jan 23 '15 at 06:27
  • When you say type inference do you mean writing var s2:String = "A string" is better than var s = "A string" ? – Sentry.co Aug 23 '16 at 18:48
  • With respect to build speed, yes. – Michael Dorner Aug 23 '16 at 18:50
2

The (re)compiling is a known issue that I am sure will be resolved soon. Some recommendations:

  • Use Objective C where possible - it compiles fast even if it is a part of a Swift project
  • Split code to frameworks
  • Specify types instead of leaving it up to the compiler to infer them

Again, there is a good chance that this will be fixed soon, so perhaps it is best not to make big investments in rewriting or reorganizing the code at this point in time.

MirekE
  • 11,515
  • 5
  • 35
  • 28
  • 3
    "Use Objective C" I post this question in order to avoid this, I really love Swift and would like to improve overall process at least a bit, rather to write code in Objective C. "Specify types" - makes sense, but code become not so clean. Will try to test how much impact will it bring. Thanks. – Alexey Globchastyy Jan 23 '15 at 06:40
  • About good chance that this will be fixed soon. I have same thoughts half year ago, and I still believe that this problem should be fixed soon, but don't have much time to wait :) – Alexey Globchastyy Jan 23 '15 at 06:42
1

you could try:

  • upgrading the amount of RAM in your computer
  • if you have multiple .swift files that do things on the same view controller, try condensing them into one .swift file per view controller
  • tweaking the settings under compile sources to see if you have any duplicates or if there are any scripts or settings you can add to make it compile faster...

you can also take a look at this post's answers for some hints as to what you can do to slow down compile time

Community
  • 1
  • 1
MoralCode
  • 1,954
  • 1
  • 20
  • 42
  • Thanks. I do have late 2013 MacBook Pro with 8Gb, so RAM can't be upgraded. I'm not sure that another 8-16Gb will make much difference in order to buy a new computer. Does the amount of files plays big role? If I put several classes in single file will it be faster? Would try to make some tests on it. – Alexey Globchastyy Jan 23 '15 at 06:34
  • I doubt filing will melt a difference. I think it's mostly import statements/references to other files, number of files and settings. – MoralCode Jan 23 '15 at 14:04
1

I've discovered that one of the main causes of segmentation faults and slow compilation is hardcoding big arrays and dictionaries, especially when declaring them as global constants and trying to access values from them from within another .swift file. When I store all that data inside plists, these problems are gone.

bzz
  • 5,556
  • 24
  • 26
0

In my experience avoid creating the large swift files, when I started a project in my new company, there was a 'UIViewController' with more than 2000 lines, little changes on this file taking much time to build, I made 4 extensions with <500 lines from that class, my speed improvement was incredible.

Hamed
  • 1,678
  • 18
  • 30