37

Ever since Swift 3 and Xcode 8 my project compiles quite slowly. Every time I add so much as an empty line to a file, recompiling takes a full minute. When I check the output, there is no particular file that takes very long. (I also used this tool to measure it: https://github.com/RobertGummesson/BuildTimeAnalyzer-for-Xcode)

It always appears to compile 4 files at once. The "rythm" is quite steady. Just very slow...

Also: Whenever I open or switch between files, it can take very long till I get autocomplete, or errors/warnings.

What things can I check? I almost feel like there is some flag I set that just drags down the build speed like crazy..

EDIT: This is not a solution to the underlying problem, but I spent some time on moving more code to frameworks. This made a difference (simply because it has to recompile less files every time). This shouldn't be necessary but it got unbearable... I'm of course still looking very much for a proper solution.

Cœur
  • 37,241
  • 25
  • 195
  • 267
fancy
  • 2,077
  • 2
  • 23
  • 45
  • See if [this](http://roadfiresoftware.com/2016/10/cut-your-swift-build-times-in-half-with-this-one-weird-trick/) works for you. I am guessing that you have tried the usual of restarting your mac, Xcode, project, cleaning project etc. – Yash Tamakuwala Oct 05 '16 at 17:16
  • 2
    same here. i'm having a 9 months old 15inch macbook 2,5ghz. prize was almost 3k. it behaved like the Flash in xcode 7 compaired to what happens here in xcode 8. storyboards need like a year to open and compiling time at least tripled. i just hope for updates. – David Seek Oct 05 '16 at 17:30
  • and @YashTamakuwala damnit, you build my hopes up with that link, but my `Build Active Architectures Only` is already set `YES` by default :( – David Seek Oct 05 '16 at 17:33
  • @YashTamakuwala, yes I tried that already, but thanks. – fancy Oct 05 '16 at 17:49
  • There is also a weird voodoo trick of creating a new blank project and pasting your original files into the new one. This trick is known to solve many obscure behaviours of Xcode. – Yash Tamakuwala Oct 06 '16 at 05:59
  • @YashTamakuwala, I also tried that. Thank you, but it didn't help.. – fancy Oct 10 '16 at 09:04
  • Same here! Frustrating! – AJ9 Oct 12 '16 at 10:56
  • Have you activated whole module optimization and are you building your release configuration? (It was turned on for Swift 3.0 by default) Whole module optimization needs to rebuild your entire project every time. – Palle Oct 17 '16 at 18:09
  • http://stackoverflow.com/questions/39547197/xcode-8-0-swift-3-0-slow-indexing-and-building – Omar Albeik Nov 02 '16 at 06:59
  • @fancy try my answer, I think that's the problem with you code. – bibscy Mar 09 '17 at 19:42
  • @bibscy thanks, but as stated in my question, there is no particular file that takes very long to compile. – fancy Mar 10 '17 at 10:29
  • See my answer in [this post](http://stackoverflow.com/questions/39547197/xcode-8-0-swift-3-0-slow-indexing-and-building/42844267#42844267), hope it helps. – ironarrow Mar 16 '17 at 23:06
  • This worked for me on Xcode 8.3 swift 3.1 - http://stackoverflow.com/a/40497873/1890317 I went from over a minute build to 17 seconds – uplearned.com Mar 30 '17 at 01:01

8 Answers8

28

A issue with this problem is that we don't know where is the wrong initialization/declaration . A solution that my colleague suggest is to find which function take long time to compile so:

  1. Go to Project select your target
  2. Build Settings -> Swift Compiler - Custom Flags
  3. Add to Other Swift Flags -Xfrontend -warn-long-function-bodies=50 (50 represent the time in milliseconds)

after that a warning should displayed as follow:

Getter 'frameDescription' took 108ms to type-check (limit: 50ms)

and after that you know what to do ;)

Constantin Saulenco
  • 2,353
  • 1
  • 22
  • 44
5

I've had the same issue only since upgrading to Swift 3/XCode 8 and it appears to be caused by large array literals, similar to this.

I was able to fix the issue by adding type annotations to the variables being assigned to the array literal, e.g.

let array: Array<String> = ["1", "2", "3", "4", "5", "6", "7", "8"]

instead of

let array = ["1", "2", "3", "4", "5", "6", "7", "8"]
Community
  • 1
  • 1
Ben Simon
  • 121
  • 3
  • Having large array literals currently do lead to performance issues. But (as stated in my question) there are no classes that particularly stand out in compile time. If somebody suffers from long build times he should definitely check out this possibility, but in my case it's something different. – fancy Oct 14 '16 at 08:09
  • Did you report this in a radar? This is should not be happening. I notice that it doesn't work if you say :[String] as the type. Only using the generic notation seems to solve the issue. Thanx for posting. – SmileBot Dec 19 '16 at 01:40
5

This is an issue with Xcode 8 where it does not perform incremental builds correctly. If you edit a single swift file it should compile only that file only. This has already been raised here: Xcode 8 does full project rebuild

The 4 files at a time build sounds like Xcode is performing a full rebuild of the project which should not happen again if you only modified a single line in one file.

Community
  • 1
  • 1
Vlad
  • 5,727
  • 3
  • 38
  • 59
  • 2
    I saw a note here (https://forums.developer.apple.com/thread/19342) that if any files have warnings, xcode will rebuild the entire project rather than the incremental changes. I removed my warnings and it seemed to help—ymmv – John Gibb Nov 22 '16 at 16:45
4

In my case I was using a helper function to save some data in Firebase. That function was returning a dictionary with about 20 elements and it would take about 40 mins to compile. My solution was to initialize an empty dictionary and then add the items one by one to someDict . Now it compiles in less than 30 seconds. I hope it helps.

Before

func toAnyObject() -> AnyObject {
  return
      ["BookingAmount":BookingAmount,
     "BookingNumber":BookingNumber,
     "PostCode":PostCode,
     "SelectedBathRow":SelectedBathRow,
     "SelectedBedRow":SelectedBedRow,
     "DateAndTime":DateAndTime,
     "TimeStampDateAndTime":TimeStampDateAndTime,
     "TimeStampBookingSavedInDB": TimeStampBookingSavedInDB,
     "FrequencyName":FrequencyName,
     "FrequecyAmount":FrequecyAmount,
     "insideCabinets": insideCabinets,
     "insideFridge": insideFridge,
     "insideOven": insideOven,
     "laundryWash": laundryWash,
     "interiorWindows": interiorWindows,
     "FullName":FullName,
     "SuppliesName":SuppliesName,
     "SuppliesAmount":SuppliesAmount,
     "FlatNumber":FlatNumber,
     "StreetAddress":StreetAddress,
     "PhoneNumber":PhoneNumber,
     "EmailAddress":EmailAddress] as AnyObject

}

After

  func toAnyObject() -> AnyObject {

    var someDict = [String : AnyObject]()
    someDict["BookingAmount"] = self.BookingAmount as AnyObject?
    someDict["BookingNumber"] = self.BookingNumber as AnyObject?
    someDict["PostCode"] = self.PostCode as AnyObject?
    someDict["SelectedBathRow"] = self.SelectedBathRow as AnyObject?
    someDict["SelectedBedRow"] = self.SelectedBedRow as AnyObject?
    someDict["DateAndTime"] = self.DateAndTime as AnyObject?
    someDict["TimeStampDateAndTime"] = self.TimeStampDateAndTime as AnyObject?
    someDict["TimeStampBookingSavedInDB"] = self.TimeStampBookingSavedInDB as AnyObject?
    someDict["FrequencyName"] = self.FrequencyName as AnyObject?
    someDict["FrequecyAmount"] = self.FrequecyAmount as AnyObject?
    someDict["insideCabinets"] = self.insideCabinets as AnyObject?
    someDict["insideFridge"] = self.insideFridge as AnyObject?
    someDict["insideOven"] = self.insideOven  as AnyObject?
    someDict["laundryWash"] = self.laundryWash as AnyObject?
    someDict["interiorWindows"] = self.interiorWindows as AnyObject?
    someDict["FullName"] = self.FullName as AnyObject?
    someDict["SuppliesName"] = self.SuppliesName as AnyObject?
    someDict["SuppliesAmount"] = self.SuppliesAmount as AnyObject?
    someDict["FlatNumber"] = self.FlatNumber as AnyObject?
    someDict["StreetAddress"] = self.StreetAddress as AnyObject?
    someDict["PhoneNumber"] = self.PhoneNumber as AnyObject?
    someDict["EmailAddress"] = self.EmailAddress as AnyObject?

    return someDict as AnyObject
}
bibscy
  • 2,598
  • 4
  • 34
  • 82
1

This worked for me on one of my projects.

Go to Product -> Scheme -> Edit Scheme. Select Build in left side column and uncheck "Find implicit dependencies" But this flag should remain checked when you are building the project for first time..

Source

It was a simple project and it increased one of my builds from 1 minute to 2 seconds.

On a physical Device I got these results. For one of my larger projects (42 files) in only decreased it from 2:36 to 2:20. Then I added: SWIFT_WHOLE_MODULE_OPTIMIZATION = YES to Build Settings as a user defined setting. The time went down to - 2:00

On the simulator the build was 49 seconds the first time then I used.

Go to Product -> Scheme -> Edit Scheme. Select Build in left side column and uncheck "Find implicit dependencies" But this flag should remain checked when you are building the project for first time..

and the build took 7 seconds.

I hope this helps.

uplearned.com
  • 3,393
  • 5
  • 44
  • 59
  • for me, "module optimization" decreased the build time by 30%, "no implicit dependencies" by around 70-80% (even though the latter is more a temporary setting, as it won't work after a clean, at least when using pods). – d4Rk Feb 02 '18 at 15:54
1

I was able to greatly reduce my swift project compile times by avoiding the use the Nil-Coalescing Operator and string concatenation.

In otherwords where I had something like:

let x = "one" + object.nullableProperty ?? ""

I changed it to

let x = String(format: "one %@", object.nullableProperty ?? "")

My compile times have dropped drastically- from 20 minutes to 20 seconds.

Nikolay Kostov
  • 16,433
  • 23
  • 85
  • 123
Logan Sease
  • 372
  • 3
  • 5
0

Make sure you're not combining arrays like let combinedArrays = array1 + array2. There's a known bug as well for type inference here, where Swift wastes time trying to figure out what type the combinedArrays should be. Instead, [array1, array2].joined() should work just as well, and compile far faster.

Dylan Gattey
  • 1,713
  • 13
  • 34
0

One common practice that slows down compile time is using Array.append and String.append (or their + operator equivalents). For Strings, it's better to use a formatted string, so instead of

let hello = "Hello, "
let world = "World!"
let combinedString = hello + world

you should use

let combinedString = "\(hello)\(world)"

I can't remember the exact speedup, but it was on the order of 10 times for those particular lines. Odds are, thought, that this won't have a noticeable speedup for any but the tinest projects. For example, our project has hundreds of Swift files, as well as many Objective-C ones, and our compile times are often 10 minutes or more, sometimes even when the only change was to a non-Swift file.

NRitH
  • 13,441
  • 4
  • 41
  • 44