iPhone: Suppress NSLog in production? - iphone

I got a bunch of NSLog statements in my code. Is there anyway I can suppress them from executing in production, but execute when I'm developing? I want to not comment them out, and them put them back in when developing, as it's a hassle.

DEBUG is a macro that is only defined (xcode default) when you are doing a debug/development build of your project. This will cause any code between the #ifdef DEBUG and #endif lines to not be included when doing a release build but they will be compiled and included with a debug/dev/test build.
Example:
#ifdef DEBUG
NSLog(#"Hello World!");
#endif
This is what I use in my Project-Prefix.pch file (called with DEBUGLOG(#"abc %#", someStr);):
#ifdef DEBUG
extern void DBGQuietLog(NSString *format, ...);
#define DEBUGLOG(fmt, ...) DBGQuietLog((#"[Line: %d] %s: " fmt), __LINE__, __FUNCTION__, ##__VA_ARGS__);
#else
#define DEBUGLOG(fmt, ...)
#endif
#ifdef DEBUG
void DBGQuietLog(NSString *format, ...) {
if (format == nil) {
printf("nil\n");
return;
}
va_list argList;
va_start(argList, format);
NSString *s = [[NSString alloc] initWithFormat:format arguments:argList];
printf("%s\n", [[s stringByReplacingOccurrencesOfString:#"%%" withString:#"%%%%"] UTF8String]);
[s release];
va_end(argList);
}
#endif
This prints console lines (only when debugging) with line number, class name, and method name like so:
[Line: 36] -[iPhoneAppDelegate application:didFinishLaunchingWithOptions:]: Hello World!

You could make a proxy and define it as a preprocessor macro:
#ifdef DEBUG
#define MyLog(str, ...) NSLog(str, ##__VA_ARGS__)
#else
#define MyLog(str, ...)
#endif
Then you'd use MyLog() instead of NSLog() in your code and when not compiling in debug mode the NSLog would be replaced with a no-op.

As an extension to CajunLuke's answer, I can only advise you to use this: http://kdl.nobugware.com/post/2009/03/11/better-nslog/

Wrap them with a macro. It's unfortunate that Apple doesn't do this already, with a "canned" solution, but many folks do it, and there are a number of examples on the web.
Something like:
#ifdef DEBUG_MODE
#define DebugLog( s, ... ) NSLog(#"<%#:(%d)> %#", [NSString stringWithUTF8String __PRETTY_FUNCTION__], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
#else
#define DebugLog( s, ... )
#endif
(Hopefully got that right -- copied by hand from another screen)

Related

Defining one macro two values on different target in ios

I have an application having two target, I want to define a macro having different value for different target.how can i do that? both are release version
Each target has it's own "Build settings" in Xcode, there you have the "Preprocessing"-category (Look for where 'DEBUG=1' is defined) where you can set custom macros that will be unique for the target.
Do it this way
#define CONSOLE_DEBUG 1 // Comment this line to undefine
#ifdef CONSOLE_DEBUG
#define SMLog(format, ...) NSLog((#"%s (%d) " format), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
#else
#define SMLog(format, ...)
#endif
When you'll define CONSOLE_DEBUG then SMLOG will print log with Pretty function. else if you comment above line then it'll just print a simple NSLOG.
You can simple check for target Macros instead of CONSOLE_DEBUG.
EDIT:
In one of my apps I needed to give diffent URLs so Idid it with diffrent targets as follows
#ifdef APP_LIVE
#define strDefaultURL <Some URL String>
#define strIndexPlistURL <Some URL String>
#elif APP_DEV
#define strDefaultURL <Some URL String>
#define strIndexPlistURL <Some URL String>
#else
#define strDefaultURL <Some URL String>
#define strIndexPlistURL <Some URL String>
#endif
Where APP_LIVE and APP_DEV were defined in respective targets.

NSLog style debug messages from C code

I have some C code in a static library that I'm compiling into an iPhone app. I'd like to print some debug messages to the console; is there something like NSLog I should use? I'm guessing NSLog only works for the Objective-C parts of the program.
EDIT: fprintf(stdout, fmt...) and fprintf(stderr, fmt...) don't work either.. any idea why they don't? Should they work?
you can always do the classic:
fprintf(stderr, "hi, this is a log line: %s", aStringVariable);
You can make a wrapper for NSLog if you mix Objective-C code like this:
log.h
void debug(const char *message, ...) __attribute__((format(printf, 1, 2)));
log.m
#import <Foundation/Foundation.h>
#import "log.h"
void debug(const char *message,...)
{
va_list args;
va_start(args, message);
NSLog(#"%#",[[NSString alloc] initWithFormat:[NSString stringWithUTF8String:message] arguments:args]);
va_end(args);
}
and then, in your C file:
#include "log.h"
...
debug("hello world! variable: %d", num);
Other solution:
#include <CoreFoundation/CoreFoundation.h>
extern "C" void NSLog(CFStringRef format, ...);
#define MyLog(fmt, ...) \
{ \
NSLog(CFSTR(fmt), ##__VA_ARGS__); \
}
MyLog("val = %d, str = %s", 123, "abc");
While printf will show up if you're debugging from XCode, it won't show up in the Organizer Console. You can use what NSLog uses: CFLog or syslog.
#include <asl.h>
...
asl_log(NULL, NULL, ASL_LEVEL_ERR, "Hi There!");
Note that lower priority levels such as ASL_LEVEL_INFO may not show up in console.
You should be able to see printf or fprintf statements. Try running some of the code in the library but from the terminal, something should appear if not. A much more complicated (and even silly/stupid/wrong) method that I will guarantee you that will work would be:
sprintf(message,"This is a log line %s",someString);
system("echo %s",message);
If that doesn't work then you probably have something weird in your code.
Note: This will probably only work in the simulator.
You probably need to use the Apple System Log facility to get the output into the device console.
Check the functions in usr/asl.h.
asl_open
asl_new
asl_set
asl_log
asl_free
While printf will show up if you're debugging from XCode, it won't show up in the Organizer Console. You can run the following command to print only to device's console:
syslog(LOG_WARNING, "log string");
You will also need to #include <sys/syslog.h> for syslog and LOG_WARNING to be explicitly declared

How to get locale on iPhone in C++?

Everything I see about iPhone localization is, unsurprisingly, in Objective-C. The project I'm working on is already written and working on iPhone using almost entirely C++, and we have a few complete translations already. All we need now, is a way to find out the locale/language code. On the computer, this is done using getenv, checking "LANG", or if that's not set "LC_ALL". This doesn't seem to work on the iPhone (neither is set to anything), so I need some other method.
As far as I can tell, the best way to do it with Objective-C is:
NSString* languageCode = [[NSLocale preferredLanguages] objectAtIndex:0];
But then I'd have to convert from NSString* to char*/std::string (which can be done, but it's generally annoying/messy). So I'm wondering, is there an easier way to get the locale from C++ directly?
Here's what I ended up doing:
#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
#include <CoreFoundation/CoreFoundation.h>
#endif
/* ... */
#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
CFArrayRef localeIDs = CFLocaleCopyPreferredLanguages();
if (localeIDs)
{
CFStringRef localeID = (CFStringRef)CFArrayGetValueAtIndex(localeIDs, 0);
char tmp[16];
if (CFStringGetCString(localeID, tmp, 16, kCFStringEncodingUTF8))
locale = std::string(tmp); //this is the std::string
CFRelease(localeIDs);
}
#endif
Probably you want to use CFLocaleGetValue()

Conditional Compilation in assembler (.s) code for iPhone - how?

I have a few lines of assembler arm code in an .s file. Just a few routines i need to call. It works fine when building for the device, however when i switch to iPhone Simulator i get "no such instruction" errors. I tried to compile parts of the .s file conditionally with what i know:
#if !TARGET_IPHONE_SIMULATOR
But the assembler doesn't recognize these preprocessor directives (of course) and none of the conditional compilation techniques for assembler that i could remember or find worked, so i'm scratching my head now on how to avoid compilation of that assembler code when building for the Simulator. I also don't see a project option in Xcode that would allow me to compile the file or not depending on the target platform.
SOLVED:
All i was missing was the proper #import in the assembler file. I did not think of adding it because Xcode syntax highlighted any preprocessor directive in green (comment) which made me assume that these commands are not recognized when in fact they work just fine.
This works:
#import "TargetConditionals.h"
#if !TARGET_IPHONE_SIMULATOR
... asm code here ...
#endif
You do do it with a pre-processor macro. They are defined in TargetConditionals.h TARGET_IPHONE_SIMULATOR should be there! (You do need to #include it however.)
Here is code I use to detect ARM vs Thumb vs Simulator:
#include "TargetConditionals.h"
#if defined(__arm__)
# if defined(__thumb__)
# define COMPILE_ARM_THUMB_ASM 1
# else
# define COMPILE_ARM_ASM 1
# endif
#endif
#if TARGET_IPHONE_SIMULATOR
// Simulator defines
#else
// ARM or Thumb mode defines
#endif
// And here is how you might use it
uint32_t
test_compare_shifted_operand(uint32_t w1) {
uint32_t local;
#if defined(COMPILE_ARM_ASM)
const uint32_t shifted = (1 << 8);
__asm__ __volatile__ (
"mov %[w2], #1\n\t"
"cmp %[w2], %[w1], lsr #8\n\t"
"moveq %[w2], #10\n\t"
"movne %[w2], #11\n\t"
: \
[w1] "+l" (w1),
[w2] "+l" (local)
: \
[shifted] "l" (shifted)
);
#else // COMPILE_ARM_ASM
if ((w1 >> 8) == 1) {
local = 10;
} else {
local = 11;
}
#endif // COMPILE_ARM_ASM
return local;
}

How can I generate unique values in the C preprocessor?

I'm writing a bunch of related preprocessor macros, one of which generates labels which the other one jumps to. I use them in this fashion:
MAKE_FUNNY_JUMPING_LOOP(
MAKE_LABEL();
MAKE_LABEL();
)
I need some way to generate unique labels, one for each inner MAKE_LABEL call, with the preprocessor. I've tried using __LINE__, but since I call MAKE_LABEL inside another macro, they all have the same line and the labels collide.
What I'd like this to expand to is something like:
MAKE_FUNNY_JUMPING_LOOP(
my_cool_label_1: // from first inner macro
...
my_cool_label_2: // from second inner macro
...
)
Is there a way to generate hashes or auto-incrementing integers with the preprocessor?
If you're using GCC or MSVC, there is __COUNTER__.
Other than that, you could do something vomit-worthy, like:
#ifndef USED_1
#define USED_1
1
#else
#ifndef USED_2
#define USED_2
2
/* many many more */
#endif
#endif
I use this:
#define MERGE_(a,b) a##b
#define LABEL_(a) MERGE_(unique_name_, a)
#define UNIQUE_NAME LABEL_(__LINE__)
int main()
{
int UNIQUE_NAME = 1;
return 0;
}
... and get the following:
int main()
{
int unique_name_8 = 1;
return 0;
}
As others noted, __COUNTER__ is the easy but nonstandard way of doing this.
If you need extra portability, or for other cool preprocessor tricks, the Boost Preprocessor library (which works for C as well as C++) will work. For example, the following header file will output a unique label wherever it's included.
#include <boost/preprocessor/arithmetic/inc.hpp>
#include <boost/preprocessor/slot/slot.hpp>
#if !defined(UNIQUE_LABEL)
#define UNIQUE_LABEL
#define BOOST_PP_VALUE 1
#include BOOST_PP_ASSIGN_SLOT(1)
#undef BOOST_PP_VALUE
#else
#define BOOST_PP_VALUE BOOST_PP_INC(BOOST_PP_SLOT(1))
#include BOOST_PP_ASSIGN_SLOT(1)
#undef BOOST_PP_VALUE
#endif
BOOST_PP_CAT(my_cool_label_, BOOST_PP_SLOT(1)):
Sample:
int main(int argc, char *argv[]) {
#include "unique_label.h"
printf("%x\n", 1234);
#include "unique_label.h"
printf("%x\n", 1234);
#include "unique_label.h"
return 0;
}
preprocesses to
int main(int argc, char *argv[]) {
my_cool_label_1:
printf("%x\n", 1234);
my_cool_label_2:
printf("%x\n", 1234);
my_cool_label_3:
return 0;
}
I can't think of a way to automatically generate them but you could pass a parameter to MAKE_LABEL:
#define MAKE_LABEL(n) my_cool_label_##n:
Then...
MAKE_FUNNY_JUMPING_LOOP(
MAKE_LABEL(0);
MAKE_LABEL(1);
)
You could do this:
#define MAKE_LABEL() \
do { \
my_cool_label: \
/* some stuff */; \
goto my_cool_label; \
/* other stuff */; \
} while (0)
This keeps the scope of the label local, allowing any number of them inside the primary macro.
If you want the labels to be accessed more globally, it's not clear how your macro "MAKE_FUNNY_JUMPING_LOOP" references these labels. Can you explain?
It doesn't seem possible with a standard preprocessor, although you could fake it out by putting parameters within MAKE_LABEL or MAKE_FUNNY_JUMPING_LOOP, and use token pasting to create the label.
There's nothing preventing you from making your own preprocessing script that does the automatic increment for you. However, it won't be a standard C/C++ file in that case.
A list of commands available: http://www.cppreference.com/wiki/preprocessor/start