Remove println() for release version iOS Swift
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)
}
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.
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.
The
println()
function has been replaced byprint()
To use the
#if DEBUG
macro then you have to define the "Swift Compiler - Custom Flags -Other Flags" to contain the value-D DEBUG
I would recommend overriding the
Swift.print()
function in the global scope so that you can use theprint()
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.