Xcode 6 with Swift super slow typing and autocompletion

Solution 1:

  • Quit Xcode and restart the Mac are not required but preferred.
  • Delete the content of the folder ~/Library/Developer/Xcode/DerivedData
  • Delete the content ~/Library/Caches/com.apple.dt.Xcode

This is a temporally solution, but works greatly.

Below the script using Script Editor app.

tell application "Terminal"
    do script "rm -frd ~/Library/Developer/Xcode/DerivedData/*"
    do script "rm -frd ~/Library/Caches/com.apple.dt.Xcode/*"
end tell

Alternatively, you can create an alias for your terminal like this:

alias xcodeclean="rm -frd ~/Library/Developer/Xcode/DerivedData/* && rm -frd ~/Library/Caches/com.apple.dt.Xcode/*"

You can add that to your ~/.bash_profile and then type xcodeclean on the command line every time you would like to clear those two folders.

Solution 2:

I also experienced 100%+ CPU while typing some "simple" code. Some small tricks to make the swift-parser quicker by the way you structure your code.

Don't use the "+" concatinator in strings. For me this triggers the slowness very quickly. Each new "+" brings the parser to a crawl, and it has to reparse the code everytime you add a new char somewhere in your function body.

Instead of:

var str = "This" + String(myArray.count) + " is " + String(someVar)

Use the template-syntax which seems much more efficient to parse in swift:

var str = "This \(myArray.count) is \(someVar)"

This way i basically notice no limit in strlen with inline vars "\(*)" .

If you have calculations, which use + / * - then split them into smaller parts.

Instead of:

var result = pi * 2 * radius 

use:

var result  = pi * 2
    result *= radius

It might look less efficient, but the swift parser is much faster this way. Some formulas won't compile, if they have to many operations, even if they are mathematically correct.

If you have some complex calculations then put it in a func. This way the parser can parse it once and does not have to reparse it everytime you change something in your function body.

Because if you have a calculation in your function body then somehow the swift parser checks it everytime if the types, syntax etc. are still correct. If a line changes above the calculation, then some vars inside your calculation / formula might have changed. If you put it in an external function then it will be validated once and swift is happy that it will be correct and does not reparse it constantly, which is causing the high CPU usage.

This way i got from 100% on each keypress to low CPU while typing. For example this 3 lines put inline in your function body can bring the swiftparser to a crawl.

let fullPath =  "\(NSHomeDirectory())/Library/Preferences/com.apple.spaces.plist"
let spacesData  = NSDictionary(contentsOfFile: fullPath )! // as Dictionary<String, AnyObject>
let spaces : AnyObject   = spacesData["SpacesDisplayConfiguration"]!["Management Data"]!!["Monitors"]!![0]["Spaces"]!! 

println ( spaces )

but if i put it in a func and call it later , swiftparser is much quicker

// some crazy typecasting here to silence the parser
// Autodetect of Type from Plist is very rudimentary, 
// so you have to teach swift your types
// i hope this will get improved in swift in future
// would be much easier if one had a xpath filter with
// spacesData.getxpath( "SpacesDisplayConfiguration/Management Data/Monitors/0/Spaces" ) as Array<*> 
// and xcode could detect type from the plist automatically
// maybe somebody can show me a more efficient way to do it
// again to make it nice for the swift parser, many vars and small statements
func getSpacesDataFromPlist() -> Array<Dictionary<String, AnyObject>> {
  let fullPath =  "\(NSHomeDirectory())/Library/Preferences/com.apple.spaces.plist"

  let spacesData  = NSDictionary(contentsOfFile: fullPath )!    as Dictionary<String, AnyObject>
  let sdconfig    = spacesData["SpacesDisplayConfiguration"]    as Dictionary<String, AnyObject>
  let mandata     = sdconfig["Management Data"]                 as Dictionary<String, AnyObject> 
  let monitors    = mandata["Monitors"]                         as Array<Dictionary<String, AnyObject>> 
  let monitor     = monitors[0]                                 as Dictionary<String, AnyObject>
  let spaces      = monitor["Spaces"]                           as Array<Dictionary<String, AnyObject>>

  return spaces
}

func awakeFromNib() {
  ....
  ... typing here ...

  let spaces = self.getSpacesDataFromPlist()
  println( spaces) 
}

Swift and XCode 6.1 is still very buggy, but if you follow these simple tricks, editing code becomes acceptable again. I prefer swift a lot, as it gets rid of .h files and uses much cleaner syntax. There is still many type-casting needed like "myVar as AnyObject" , but thats the smaller evil compared to complex objective-c project structure and syntax.

Also another experience, i tried the SpriteKit, which is fun to use, but its quite in-efficient if you don't need a constant repaint at 60fps. Using old CALayers is much better for the CPU if your "sprites" don't change that often. If you don't change the .contents of the layers then CPU is basically idle, but if you have a SpriteKit app running in background, then videoplayback in other apps might start to stutter due to the hardlimited 60fps update-loop.

Sometimes xcode shows odd errors while compiling, then it helps to go into menu "Product > Clean" and compile it again, seems to be a buggy implementation of the cache.

Another great way to improve parsing when xcode gets stuck with your code is mentioned in another stackoverflow post here. Basically you copy all contents from your .swift file into an external editor, and then function by function copy it back and see where your bottleneck is. This actually helped me to get xcode to a reasonable speed again, after my project went crazy with 100% CPU. while copying your code back, you can refactor it and try to keep your function-bodies short and functions/formulars/expressions simple (or split in several lines).