Swift presentViewController completion block working only in debug not called in release

Andrea Bozza picture Andrea Bozza · Mar 16, 2015 · Viewed 10.3k times · Source

I have a strange behaviour with a completion block in Debug and Release. For example:

        sourceViewController.presentViewController(ccVC, animated: true, completion: { () -> Void in
            NSUserDefaults.standardUserDefaults().setBool(true, forKey: kChromeCastInstructionsShown)
            NSUserDefaults.standardUserDefaults().synchronize()
            println("save bolean")
        })

In debug: println("save bolean") print string In relase: println("save bolean") print nothing

Any idea about this behaviour? Someone experiment a clear solution?

Kind Andrea

Answer

Yoichi Tagaya picture Yoichi Tagaya · Mar 16, 2015

It looks a Swift compiler bug (at least version 1.1) discussed here: https://github.com/ReactiveCocoa/ReactiveCocoa/issues/1632

In a release build, closures are not invoked sometimes especially when they are sequenced like:

array.map({ $0 * 2 }).map({ $0 * 3 }).map({ $0 * 4 })...

The problem appears in Swift only, not in Objective-C. It can be workarounded by setting Swift Compiler Optimization Level to None [-Onone] if your app does not require the better performance by the optimization.

Screenshot

Or another workaround is naming the closure as a function:

func completionHandler() {
    NSUserDefaults.standardUserDefaults().setBool(true, forKey: kChromeCastInstructionsShown)
    NSUserDefaults.standardUserDefaults().synchronize()
    println("save bolean")
}

sourceViewController.presentViewController(ccVC, animated: true, completion: completionHandler)

I take the former workaround for my project because I want to keep my code simple and don't need the performance enhancement by the optimization.