Is there any way to completely remove logs from a final release build of an application written in Swift? By completely I mean that if I open the compiled binary file in a text/hex editor there should be no logged strings in it and if someone disassembles the binary file also he should not see any logged strings in a disassembler.
I know that I can disable writing the logs to the console in release build with #if DEBUG for example with something like this:
func log(_ message: String) {
#if DEBUG
print(message)
#endif
}
But when using this approach logged strings are still visible in compiled binary (and could for example help someone in analysing disassembled code of the application). They are just not printed on the console and that is not acceptable for me. I want to remove them completely from compiled binary. In Objective-C we could use preprocesor macros to achieve that but they are not available in Swift. I could put #if DEBUG before each occurrence of log/print function in the code and that would work but obviously this is not a great solution as it would require to add this #if DEBUG in hundreds of places. Alternatively I could just do find and replace to comment all print/log calls before building a release build but this is also not a great solution as I would need to comment and uncomment those logs each time I build the release version. Is there any better way to achieve that?
You could try using the the Logger framework provided by Apple
It is more performant that print statements, and you have more control over what is logged - for developing and debugging you can use the debug log level. There are other logging levels that generate messages during run time with privacy options.
There is a WWDC Video which you may find useful to introduce you to this.
Related
This looked promising but doesn't seem like a duplicate question as it addresses issues in Swift.
I am finalising an existing Objective C project but NSLog disappeared when I updated to Xcode 9. So I'm looking for some setting in Xcode that lets me continue using NSLog to fine tune the project.
Basic debugging using logging for Swift and Objective-C apps appears to have changed in Xcode 9 as NSLog messages no longer appear in the Debug area. The window where DEBUG=1 is set no longer looks like Figure 2 The DEBUG preprocessor macro setting in an Xcode project.
As an example, I want to display this string message in the Debug area using Xcode9.
NSString *outputData = #"This should show in Debug area";
NSLog( #"text: %#", outputData );
I studied the latest documentation here or here but so far that has not helped. It may also be worth noting that previously the Debug area would open automatically when I ran the project. Since installing Xcode9 it no longer does that.
Hopefully the extra information provided in the edits below will suggest to someone where I have yet to look. Thanks.
EDIT 1
In the Console area - i.e. the bottom right part of the Debug area - I had All Output selected. So I tried using Debugger output and Target output but there was still no log.
I added these statements in the Prefix.pch file
#ifndef DEBUG
#define NSLog(...) /* suppress NSLog when in release mode
#endif
When I ran the code the following appeared in the Issue Navigator.
Unused variable 'outputData'
EDIT 2
There seems to be a different place to set DEBUG=1 in Xcode9 (see below).
I inserted a DEBUG macro into the .pch file using the examples suggested in several SO posts here, here, here (all quite old) and even here (making sure to change MyLog back to NSLog). And in each case I was able to report the same issue in the Issue navigator but never in the Debug console. A similar problem (with Xcode5) was solved here by copying over the files into a new project but I want to avoid this.
My app which was almost finished has so far not had to deal with any of the complex issues that unified logging seeks to address. But I watched the 2016 WWDC video on unified logging and read through its slide show files searching for an example of how to use the appropriate API to do something as basic - print NSLog live to the console area - the way I did before installing Xcode9. This may be the wrong approach. But I can’t think of a better way to proceed.
EDIT 3
It's worth noting that when I created a new Objective C project using Xcode9 and ran the above code, the string message appeared in the Console area.
In other words, using Xcode9 the new logging API does work with NSLog, but only for a new project and not for one created using an earlier version of Xcode.
Enable DEBUG preprocessor macro
Rather than writing your debug statement into code, you might try dropping in a breakpoint, right clicking on it, and selecting "Edit Breakpoint". You should see this menu:
From there, you'll click "Edit Breakpoint" and you're presented with this:
From there, you can click "Action" and you'll see this menu:
You can enter print messages (ex: myMethodCalled) or variable values (myIntValue = #myIntValue#), or you can type debugger commands to execute at that spot in the code (ex: po dump(myArray)).
The downside of this approach is the breakpoints aren't always "sticky" to the line of code you originally drop it in on.
Try this. Navigate to:
Product -> Scheme -> Edit Scheme -> Run -> Arguments -> Environment Variables
in Xcode.
Add OS_ACTIVITY_MODE and set the value to disable or leave it empty.
Make sure it is checked!
Hope this helps
A Debug log was enabled in the Console area of Xcode9 after replacing these definitions in the preCompile header
#ifndef DEBUG
#define NSLog(...) /* suppress NSLog when in release mode */
#endif
with the following
#ifdef __DEBUG__
#define NSLog(...) /* suppress NSLog when in release mode */
#endif
Environment Variables for Arguments were set according to the answer above with an additional setting for Options. Someone more familiar with the unified logging API might explain the particular options but I'm satisfied I have a working solution.
Arguments
Options
When developing iOS apps using XCode, you can use NSLog calls to write information to the console for debugging. In Xamarin.iOS, the same can be done with Console.WriteLine.
When running a release build of an app, without the debugger attached, these calls serve no purpose. So I've thought of excluding them with pre-processor directives:
#if DEBUG
Console.WriteLine("foo");
#endif
So that the calls don't even exist in the release build. I appreciate this may be micro-optimisation - but I'm curious if Xamairn already does this, making this unnecessary?
Console output is not removed in iOS release builds.
FYI: Xcode does not "automatically" remove NSLog or print from Obj-C/Swift "release" code either. (You typically define a single global preprocessor macro to remove them all, if desired...)
Your options are many... including:
DEBUG preprocessor as you show in your question.
Use System.Diagnostic.Debug.WriteLine:
Any calls to Debug.* will be removed by the compiler due to the [Conditional("DEBUG")] attribute being applied.
Create your own "Logger" class as a wrapper to the stdout writers and [Conditional("DEBUG")] it
Use Fody and re-weave the assemblies to remove/NOP/redirect the WriteLine
I do this to redirect the calls to in internal log and upon crash or user stat requests, forward this log to our crash reporting servers.
etc, .....
Ref: Xamarin's NSLogWriter Helper Class
I'm having a problem with breakpoints in the source code of a specific library / framework (new to Xcode - i'm not sure what the correct term is) in a fairly large iOS project. I have all the code for this library. Breakpoints are working fine everywhere else, but in this one specific library, all breakpoints are ignored.
I can put a breakpoint in a function called from within one of those source files, and it will trigger, but then the callstack shows "__lldb_unnamed_function" for the location in the file i'm interested in, as if the symbols have been stripped.
I have the following settings for the library in question
Generate Debug Symbols = YES
Strip Debug Symbols During Copy = NO
Strip Linked Product = NO
Dead Code Stripping = NO
I have been using a lot of #ifdefs to test alternate implementations of a few functions so i thought some stuff might be getting marked as dead code by accident (hence that last setting). I already tried clean/rebuild. I tried completely removing the app from the target iPhone. I tried deleting intermediate file folder under
/Library/Developer/Xcode/DerivedData
The code is definitely executing because all my NSLog calls show up properly.
I don't have much experience with Xcode so i'm hoping i'm just missing something simple
Thanks
Some part of your build process must be stripping this binary. If you were generating an unstripped binary with no debug information, then you would see full symbol names in backtraces and the like, you just wouldn't have debug information for them.
The only good way to figure out who is doing this is to look at the full build log in Xcode, and expand each of the stages and grub through all the build stages to figure out who is doing this. You expand the stages by hovering over each build line on the RHS and you'll get a disclosure dingus that looks like a bunch of lines on a page; click that to see the real commands.
Another way to finesse this may be to build the dSYM for this framework (by setting the Debug Format to "DWARF + dSYM".) That should get made before anything gets stripped, so unless whoever is stripping this is being awfully clever this should preserve the debug information.
I have a static library which I use this iOS Framework Script to generate a .framework file and distribute to developers.
But, currently there is an issue appeared that it only happens when packaging and using the .framework in a client application! When using the static library by the way it works perfect, NSLog and the problem I have it's not reproducing.
What I want to ask is, why I lost my NSLog messages? Does this have to do with debug/release scheme configuration? The framework script does not seem to remove with any configuration in the command line the debug logging, I don't remember anyway if in release it removes the NSLogs?!
Any thoughts how to make my debug NSLog messages appear again, maybe a setting that I switched values and now banging my head to find and resolve the issue?
I found the proper way to use log messages with level as instructed by Apple using the ASL (Apple Logging System).
https://developer.apple.com/library/mac/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/LoggingErrorsAndWarnings.html#//apple_ref/doc/uid/10000172i-SW8-SW1
That said using this great wrapper by Mike Weller did the job and I can control better the logging to console plus I finally have console output from my static framework.
I have an iOS project which has a static library and in the library there is a encrypt method and in the method it refers a lot of system encrypt method about AES encryption. When I build the static library with release,it returned the correct data.But when I build with debug mode,it returns nil.
What's the differences between the two modes?
The same source code can build out different binary files that works differently?
Help me,thanks beforehand. This is where I choose the two modes.
The main difference is the level of compiler optimization. Select the project target and look at the Build Settings and compare Debug to Release.
One potential reason for the crash is that the code has some memory usage errors that by coincidence do not cause a crash with code optimization but do with no optimization. Or there are some other configuration difference. See the comment by #iDev.
A starting point is to fix all warnings, both compiler and Analyzer. The examine the crash log to understand the crash. If you need help with that add a crash report to your question.