Is it possible to disallow the use of NSLog, so that it will come up as an error if used at compile time?
Ideally some sort of compiler flag with the name of the method that is disallowed?
Thanks
If you re-declare NSLog (and perhaps also NSLogv) as
void NSLog(NSString *format, ...) UNAVAILABLE_ATTRIBUTE;
void NSLogv(NSString *format, va_list args) UNAVAILABLE_ATTRIBUTE;
in your precompiled header file, you get a nice error message:
main.m:199:3: error: 'NSLog' is unavailable
NSLog(#"%#", s1);
^
You can even provide a custom error message (found in Messages on deprecated and unavailable Attributes of the Clang documentation):
void NSLog(NSString *format, ...) __attribute__((unavailable("You should not do this!")));
main.m:202:3: error: 'NSLog' is unavailable: You should not do this!
NSLog(#"%#", s1);
^
In your prefix header:
#define NSLog(x, ...) (__please_dont_use_NSLog__)
Try this!
#ifdef DEBUG
# define NSLog(...) NSLog(__VA_ARGS__)
#else
# define NSLog(...)
#endif
The solution can be found here: Enable and Disable NSLog in DEBUG mode
Hope this helped!
Related
Here is my customized NSLog.
#define NSLog(fmt, ...) printf("🌳🌳🌳%s,%d\n %s\n\n", __PRETTY_FUNCTION__, __LINE__, [NSString stringWithFormat:fmt, ##__VA_ARGS__].UTF8String)
This log is work good on another project, but it occurred 4 error when compiler time in current project. If using __VA_ARGS__, like #define NSLog(...) NSLog(__VA_ARGS__), it's going to compile successful. I think that maybe caused in Building Setting.
It's anyone has any idea to help me to solve this.
Check that the header file declaring this imports Foundation. Check that you don't have NSLog defined somewhere else as well and finally, really not a good idea to redefine NSLog. You're probably better off adopting a logging framework or defining your own like this:
#define MELog(fmt, ...) NSLog("🌳🌳🌳%s,%d\n %s\ ....
I've below code in my project dlog should print the values in console if isConsoleLogActive is YES.
It gives error like Operator 'defined' requires an identifier
#if defined ([Util isConsoleLogActive])// Operator 'defined' requires an identifier in this line
#define DLog(...) NSLog(__VA_ARGS__)
#define DTrace() NSLog(#"%s", __PRETTY_FUNCTION__)
#else
#define DLog(...) /* */
#define DTrace() /* */
#endif
if I use the same code([Util isConsoleLogActive]) in my .m it works perfectly fine. I face this issue only in #define
What could be the issue. Please give me some idea.
The various commands that start with # are preprocessor directives. These get executed before the compilation phase at build time, before your application actually executes. You should use the preprocessor directives to conditionally include different code in your application based on build configuration. The preprocessor, however, is the wrong way to handle conditional execution on a specific platform at runtime; for that, you want your standard "if...else" logic.
If your goal with that statement is to determine if the given selector exists, try respondsToSelector, instead.
Result of
[Util isConsoleLogActive]
is not known at compile-time. So you can not use it with '#if defined'.
I'm developing one logger class for my application.NSLog will be printed only in debug mode. I have customized the NSLog where Name of the source file,Source code line number,Name of the class and method where NSLog() was called is printed.
That is , my current NSLOG looks like
(ClassName MethodName) (SourceFileName:LineNumber) NSLog output
Now, I want to log, parameter values of the methodname. How to get those parameter values in NSLog???
I want the output as
(ClassName MethodName) (SourceFileName:LineNumber) (Parameter Values) NSLog output
Something like this should work
#define InstanceLog(fmt, ...) NSLog(#"(%#.%#)(%s:%d) " fmt, NSStringFromClass(self.class), NSStringFromSelector(_cmd), __FILE__, __LINE__, ##__VA_ARGS__)
You may use it as NSLog within Objective-C methods
InstanceLog(#"simple string");
InstanceLog(#"%# %#", #"hello", #"world");
There isn't a way to automatically introspect the values passed to a method. Even in DEBUG builds (where the optimizer is out of the way), any attempts to write code to introspect said iVars is going to be incredibly complex (you'll have to dive into the symbol tables, extract offsets, etc, and then try and find the arguments that were likely destroyed in the attempt to grab them).
So, no, no way to really automate that.
In general, though, any such logging mechanism would generate such an atrociously huge amount of output that you are far better off creating (potentially debugging only) logging that is both configurable and highly tuned to your application.
You can pass args like this (thanks to #hoha for the simpler version).
#import <Foundation/Foundation.h>
#define FooLog(fmt, ...) NSLog(#"(%s): %#", __PRETTY_FUNCTION__, ## __VA_ARGS__)
#interface Bob:NSObject
#end
#implementation Bob
- (void)yourUncle
{
FooLog(#"%#", self);
}
#end
int main(int argc, char *argv[]) {
#autoreleasepool {
NSString *w = #"World";
FooLog(#"Hello, %#!", w);
[[Bob new] yourUncle];
}
}
Output:
2013-09-02 10:51:49.447 Untitled[60967:507] (int main(int, char **)): Hello, World!
2013-09-02 10:51:49.453 Untitled[60967:507] (-[Bob yourUncle]): <Bob: 0x7fde8840a490>
for handle custom logging you can use or refer following link.
You can customise Lumberjack as per you needs.
Lumberjack error logging for ios
Lumberjack error logging tutorial
I am trying to create a custom NSLog() method , DNSLog() , which executes the NSLog only if the debug variable is true.
-(void)DNSLog:(NSString *)formatString, ...
{
if(debug){
va_list args;
va_start(args, formatString);
NSLog([[NSString alloc] initWithFormat:formatString arguments:args]);
va_end(args);
}
}
But when I try calling it using
DNSLog(#"Hello %d",x);
I receive a compilation error :
Undefined symbols for architecture i386:
"_DZNSLog", referenced from:
-[RestaurantInfoViewController viewDidLoad] in RestaurantInfoViewController.o
ld: symbol(s) not found for architecture i386
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I have used this as a reference : http://www.cocoawithlove.com/2009/05/variable-argument-lists-in-cocoa.html
Where am I going wrong ?
You have confused methods and functions - Objective-C has both. NSLog is a standard function so you call it as NSLog(...). You have defined a method:
-(void)DNSLog:(NSString *)formatString, ...
but tried to call it as a function. To call your method you need to do:
[self DNSLog:#"Hello %d", x];
As your code compiles you must have a global or instance debug variable. If it is a global then you could define DNSLog as a function (this won't work if debug is an instance variable as only methods can directly access those). The function would start:
void DNSLog(NSString *formatString, ...)
The body of the function will be the same as for the method.
NSLog also has an attribute, NS_FORMAT_FUNCTION, on it to tell the compiler that it takes a format string as an argument, seeing this the compiler will check the format string and arguments to see that they match. To do this for your method or function write:
-(void)DNSLog:(NSString *)formatString, ... NS_FORMAT_FUNCTION(1,2);
or:
void DNSLog(NSString *formatString, ...) NS_FORMAT_FUNCTION(1,2);
in the interface or header file.
HTH.
Instead of using a custom method, try adding this macro to your app, perhaps in your .pch file.
#ifdef DEBUG
#define MyLog(x, ...) NSLog(#"%s %d: " x, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#else
#define MyLog(x, ...)
#endif
This will run a custom log I call MyLog when in debug mode, and when in release, it wont do anything. It also prints out some other useful information like the file and line number of the log.
Thank You everyone for your extremely 'valuable', 'encouraging' and 'supporting' answers to a beginner.
I found my mistake and here is the corrected working code :
void ZNSLog(NSString *format, ...){
if(!ENABLE_DEBUGGING)
return;
va_list args;
va_start(args, format);
NSLogv(format, args);
va_end(args);
}
ZNSLog(#"Hello");
The previous method I was using was an Objective C method
-(void)DNSLog:(NSString *)formatString, ...
which I was trying to call using a C function Call.
I want to treat any NSLog in my code as an error. The line should be a compile time error in Xcode. Just like how usage of release in an ARC enabled project is treated as an error.
Try this,
#define NSLog_UNAVAILABLE __attribute__((unavailable("NSLog is treated as Error.")))
FOUNDATION_EXPORT void NSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2) NSLog_UNAVAILABLE;
You can redeclare prototype of NSLog in your code with __deprecated, so any use of it will produce warning:
FOUNDATION_EXPORT void NSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2) __deprecated;
Then maybe there is some way to turn warnign into error.
You can use this if you use Clang as your compiler (actually just realised GCC also supports C11's _Static_assert too from version 4.6):
#define NSLog(...) _Static_assert(0, "Not allowed to use NSLog!")
Compilation will fail if a _Static_assert fails.