Remove println() for release version iOS Swift
As noted, i am a student and need things defined a little more clearly to follow along. After lots of research, the sequence I needed to follow is:
Click on the project name at the top of the File Navigator at the left of the Xcode project window. This is line that has the name of the project, how many build targets there are, and the iOS SDK version.
Choose the Build Settings tab and scroll down to the "Swift Compiler - Custom Flags" section near the bottom. Click the Down Arrow next to Other Flags to expand the section.
Click on the Debug line to select it. Place your mouse cursor over the right side of the line and double-click. A list view will appear. Click the + button at the lower left of the list view to add a value. A text field will become active.
In the text field, enter the text -D DEBUG
and press Return to commit the line.
Add a new Swift file to your project. You are going to want to make a custom class for the file, so enter text along the lines of the following:
class Log {
var intFor : Int
init() {
intFor = 42
}
func DLog(message: String, function: String = __FUNCTION__) {
#if DEBUG
println("\(function): \(message)")
#endif
}
}
I was having trouble getting the class to be accepted by Xcode today, so the init may be a bit more heavyweight than necessary.
Now you will need to reference your custom class in any class in which you intend to use the new custom function in place of println()
Add this as a property in every applicable class:
let logFor = Log()
Now you can replace any instances of println()
with logFor.DLog()
. The output also includes the name of the function in which the line was called.
Note that inside class functions I couldn't call the function unless I made a copy of the function as a class function in that class, and println()
is also a bit more flexible with the input, so I couldn't use this in every instance in my code.
The way to hide(skip) print() and debugPrint() in Swift
You don't need to do all of that... this will be effectively the same thing:
func print(_ items: Any..., separator: String = " ", terminator: String = "\n") {
#if DEBUG
items.forEach {
Swift.print($0, separator: separator, terminator: terminator)
}
#endif
}
You might also want to take a look at this answer for a little more discussion: https://stackoverflow.com/a/38335438/6257435
Swift 2 print(), how to hide?
For swift 2.2, here's what I use:
// Disable print for production.
func print(items: Any..., separator: String = " ", terminator: String = "\n") {
#if DEBUG
Swift.print(items[0], separator:separator, terminator: terminator)
#endif
}
Do I need to disable NSLog before release Application?
One way to do it is to go into your Build settings and under the Debug configuration add a value to "Preprocessor Macros" value like:
DEBUG_MODE=1
Make sure you only do this for the Debug configuration and not for Beta or Release versions. Then in a common header file you can do something like:
#ifdef DEBUG_MODE
#define DLog( s, ... ) NSLog( @"<%p %@:(%d)> %@", self, [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
#else
#define DLog( s, ... )
#endif
Now instead of NSLog
use DLog
everywhere. When testing and debugging, you'll get debug messages. When you're ready to release a beta or final release, all those DLog
lines automatically become empty and nothing gets emitted. This way there's no manual setting of variables or commenting of NSLogs
required. Picking your build target takes care of it.
Should I release an app to the App Store with print statements in it?
I assume you are using Swift, then print
is completely safe, even for AppStore builds. You are not going to be rejected and it's not a security risk either.
print
, unlike similar NSLog
, is not going to produce any logs anywhere that would be visible to the user (e.g. in Xcode Device Console).
More info on the difference between print
and NSLog
: Swift: print() vs println() vs NSLog()
Disabling NSLog For Production In Swift Project
You'll need to set up a compiler flag to use the Swift preprocessor - go to the Swift Compiler - Custom Flags section of Build Settings to set up a -D DEBUG
flag:
Then in your code you can define a DLog()
function and only print your message if the DEBUG
flag is set:
func DLog(message: String, function: String = #function) {
#if DEBUG
println("\(function): \(message)")
#endif
}
Does print() / println() slow execution?
Yes it does slow the code.
Both print
and println
decrease performance of the application.
Println problem
println
is not removed when Swift does code optimisation.
for i in 0...1_000 {
println(i)
}
This code can't be optimised and after compiling Assembly code would perform a loop with 1000 instructions that actually don't do anything valuable.
Analysing Assembly code
The problem is that Swift compiler can't do optimal optimisation to the code with print
and println
commands.
You can see it if you have a look on generated Assembly code.
You can do see assembly code with Hopper Disassembler or by compiling Swift code to the Assembly with by using swiftc
compiler:
xcrun swiftc -emit-assembly myCode.swift
Swift code optimisation
Lets have a look on few examples for better understanding.
Swift compiler can eliminate a lot of unnecessary code like:
- Empty function calls
- Creating objects that are not used
- Empty Loops
Example:
class Object {
func nothing() {
}
}
for i in 0...1_000 {
let object = Object3(x: i)
object.nothing()
object.nothing()
}
In this example Swift complier would do this optimisation:
1. Remove both nothing
method calls
After this the loop body would have only 1 instruction
for i in 0...1_000 {
let object = Object(x: i)
}
2. Then it would remove creating Object
instance, because it's actually not used.
for i in 0...1_000 {
}
3. The final step would be removing empty loop.
And we end up with no code to execute
Solutions
- Comment out
print
andprintln
This is definitely not the best solution.//println("A")
- Use
DEBUG
preprocessor statement
With this solution you can simple change logic of your debug_print functiondebug_println("A)
func debug_println<T>(object: T) {
#if DEBUG
println(object)
#endif
}
Conclusion
Always Remove print
and println
from release application!!
If you add print
and println
instruction, the Swift code can't be optimised in the most optimal way and it could lead to the big performance penalties.
How could a print statement removal break my project? (Swift/Xcode)
Ah. Views in UIViewControllers are loaded lazily, usually by the SDK at relevant parts of the lifecycle. Which is why you do set up code in viewDidLoad
by which time the view has been loaded.
Because it is lazily loaded when you call toVC.view
in the print statement you are causing it to load.
I suspect that this line toVC.sideMenuView.frame.origin.x = toVC.view.frame.width
may be an issue. when you are setting some property of a view which is then being overwritten.
To attempt to debug this, try stepping into that line. Alternatively you could replace the print
statement with a simple _ = toVC.view
to force the view to load. Or, add some debugging statement of print(toVC.isViewLoaded)
at various points in the code to see if the view is actually being loaded.
Related Topics
Push Notification Not Receiving in Background iOS
How to Load an Uiimage into a Swiftui Image Asynchronously
How to Make a Button Continually Call a Function When Held Down (Spritekit)
Optional Binding with Try? and As? Still Produces an Optional Type
Open Phone Settings Programmatically in iOS9
Performance Testing in Swift Using Tdd
Present and Dismiss Modal View Controller
How to Save, Retrieve, Delete & Update My Data in Plist File in iOS
Command /Usr/Bin/Codesign Failed with Exit Code 1
Duplicate Symbol Error in Nsmanagedobject Subclass
How to Add Multiple Collection Views in a Uiviewcontroller in Swift
How to Center a Popoverview in Swift
Swift Doesn't Convert Objective-C Nserror** to Throws
Creating Custom Info Window in Swift with the Google Maps iOS Sdk
How to Password Protect Writing to Nfc Ntag216 Tag on iOS 13 Using Nfc Core