Remove println() for release version iOS Swift

I would like to globally ignore all println() calls in my Swift code if I am not in a Debug build. I can't find any robust step by step instructions for this and would appreciate guidance. is there a way to do this globally, or do I need to surround every println() with #IF DEBUG/#ENDIF statements?


The simplest way is to put your own global function in front of Swift's println:

func println(object: Any) {
    Swift.println(object)
}

When it's time to stop logging, just comment out the body of that function:

func println(object: Any) {
    // Swift.println(object)
}

Or you can make it automatic by using a conditional:

func println(object: Any) {
    #if DEBUG
        Swift.println(object)
    #endif
}

EDIT In Swift 2.0 println is changed to print. Unfortunately it now has a variadic first parameter; this is cool, but it means you can't easily override it because Swift has no "splat" operator so you can't pass a variadic in code (it can only be created literally). But you can make a reduced version that works if, as will usually be the case, you are printing just one value:

func print(items: Any..., separator: String = " ", terminator: String = "\n") {
    Swift.print(items[0], separator:separator, terminator: terminator)
}

In Swift 3, you need to suppress the external label of the first parameter:

func print(_ items: Any..., separator: String = " ", terminator: String = "\n") {
    Swift.print(items[0], separator:separator, terminator: terminator)
}

Updated for Swift 4.x:

With Swift 2.0/3.0 and Xcode 7/8 now out of beta, there have been some changes to how you disable the print function in release builds.

There are some important points mentioned by @matt and @Nate Birkholz above that are still valid.

  1. The println() function has been replaced by print()

  2. To use the #if DEBUG macro then you have to define the "Swift Compiler - Custom Flags -Other Flags" to contain the value -D DEBUG

  3. I would recommend overriding the Swift.print() function in the global scope so that you can use the print() function as normal in your code, but it will remove output for non-debug builds. Here is a function signature that you can add at the global scope to do this in Swift 2.0/3.0:

    func print(items: Any..., separator: String = " ", terminator: String = "\n") {
    
        #if DEBUG
    
        var idx = items.startIndex
        let endIdx = items.endIndex
    
        repeat {
            Swift.print(items[idx], separator: separator, terminator: idx == (endIdx - 1) ? terminator : separator)
            idx += 1
        }
        while idx < endIdx
    
        #endif
    }
    

Note: We have set the default separator to be a space here, and the default terminator to be a newline. You can configure this differently in your project if you would like.

Hope this helps.

Update:

It is usually preferable to put this function at the global scope, so that it sits in front of Swift's print function. I find that the best way to organize this is to add a utility file to your project (like DebugOptions.Swift) where you can place this function at the global scope.

As of Swift 3 the ++ operator will be deprecated. I have updated the snippet above to reflect this change.


The problem with all these approaches, including mine, is that they do not remove the overhead of evaluating the print arguments. No matter which of them you use, this is going to be expensive:

print(myExpensiveFunction())

The only decent solution is to wrap the actual print call in conditional compilation (let's assume that DEBUG is defined only for debug builds):

#if DEBUG
print(myExpensiveFunction())
#endif

That, and only that, prevents myExpensiveFunction from being called in a release build.

However, you can push back evaluation one level by using autoclosure. Thus, you could rewrite my solution (this is Swift 3) like this:

func print(_ item: @autoclosure () -> Any, separator: String = " ", terminator: String = "\n") {
    #if DEBUG
    Swift.print(item(), separator: separator, terminator: terminator)
    #endif
}

This solves the problem just in the case where you are printing just one thing, which is usually true. That's because item() is not called in release mode. print(myExpensiveFunction()) thus ceases to be expensive, because the call is wrapped in a closure without being evaluated, and in release mode, it won't be evaluated at all.