Nov 07, 2015:  ~ 3 min read

Code coverage issues for Swift projects

I stumbled upon a problem recently (the full story can be found on Apple Developer Forums) and the short version is: running the app or the tests without code coverage enabled always worked fine, but turning it on caused errors to appear, breaking the build process when trying to test.

Hunting attemp #75. One of the errors raised was Segmentation fault 11, which appeared for several Swift files during the Compile Swift source files phase. This is an error I remembered having in the early days of Swift when writing daring short syntax, like:

// UILabel convenience init
convenience init(text: String, font: UIFont)

// UIFont helper
class func boldFont(ofSize size: CGFloat) -> UIFont {
  return UIFont(name: "AvenirNext-Bold", size: size)!

  text: "Test",
  font: .boldFont(ofSize: 15)

// This wouldn't compile, with segmentation fault 11,
// and I would have to write the full thing, UIFont.boldFontOfSize(15)

So I went in one of the smallest Swift files with issues, added "long" syntax everywhere, and, weirdly enough, it was still not compiling.

Next, in a desperate attempt, I went ahead and stripped the code of all ternary conditions and optionals (replacing with bangs !), and it now worked. Huh?

Anyway, adding back the old code, bit by bit, revealed the culprit - variables with ternary conditioned default values, like:

private let leftMargin: CGFloat = isPad ? 32 : 16 // var made no difference
private let leftMargin: CGFloat = CGFloat((1 == 1) ? CGFloat(32) : CGFloat(16)) // desperation moment

Changing them to computed properties, or lazy variables did the trick, and now code coverage finally works:

private var leftMargin: CGFloat {
 return isPad ? 32 : 16
private lazy var leftMargin: CGFloat = {
 return isPad ? 32 : 16

This whole thing seems so simple, I have the feeling I'm just missing something obvious; please let me know if so.

Subscribe to my monthly newsletter.
No spam, unsubscribe at any time.