Custom NSLog Method ( Variadic ) - ios

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.

Related

NSLog giving error when trying to print a single unformatted integer

Hi this is third day of mine using Objective-C today I was writing few simple programs and i ecncountered the following warning
main.m:19:5: warning: passing argument 1 of 'NSLog' makes pointer from integer without a cast [enabled by default]
NSLog(res);
which finally resulted in the Segmentation fault.. Here is my program..
#import <Foundation/Foundation.h>
#interface SomeClass: NSObject
{
int x;
}
#property int x;
#end
#implementation SomeClass
#synthesize x;
#end
int main(){
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc]init];
SomeClass * obj = [[SomeClass alloc]init];
obj.x =20;
int res = obj.x;
NSLog(res); //error
/* But the error was not seen when I replaced the above statement with
NSLog(#"The value is : %d",res);
*/
[pool drain];
return 0;
}
The error message that I got was :
Compiling the source code....
$gcc `gnustep-config --objc-flags` -L/usr/GNUstep/System/Library/Libraries -lgnustep-base main.m -o demo -lm -pthread -lgmpxx -lreadline 2>&1
main.m: In function 'main':
main.m:19:5: warning: passing argument 1 of 'NSLog' makes pointer from integer without a cast [enabled by default]
NSLog(res);
^
In file included from /usr/GNUstep/System/Library/Headers/Foundation/NSObject.h:30:0,
from /usr/GNUstep/System/Library/Headers/Foundation/FoundationErrors.h:29,
from /usr/GNUstep/System/Library/Headers/Foundation/Foundation.h:33,
from main.m:1:
/usr/GNUstep/System/Library/Headers/Foundation/NSObjCRuntime.h:146:16: note: expected 'struct NSString *' but argument is of type 'int'
GS_EXPORT void NSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);
^
Executing the program....
$demo
Segmentation fault (core dumped)
Please help by making me understand why NSLog behaves like this ? Where did I go wrong?
Thank you...
You can't use the NSLog like this, You need to specify the control string and use like:
NSLog(#"%d",res);
The format should be specified for NSLog(), please check the NSLog and NSLogv reference for more information
NSLog
Logs an error message to the Apple System Log facility.
void NSLog ( NSString *format, ... );
Discussion
Simply calls NSLogv, passing it a variable number of arguments.
Availability
NSLogv
Logs an error message to the Apple System Log facility.
void NSLogv ( NSString *format, va_list args );
Discussion
Logs an error message to the Apple System Log facility (see man 3
asl). If the STDERR_FILENO file descriptor has been redirected away
from the default or is going to a tty, it will also be written there.
If you want to direct output elsewhere, you need to use a custom
logging facility.
The message consists of a timestamp and the process ID prefixed to the
string you pass in. You compose this string with a format string,
format, and one or more arguments to be inserted into the string. The
format specification allowed by these functions is that which is
understood by NSString’s formatting capabilities (which is not
necessarily the set of format escapes and flags understood by printf).
The supported format specifiers are described in “String Format
Specifiers”. A final hard return is added to the error message if one
is not present in the format.
In general, you should use the NSLog function instead of calling this
function directly. If you do use this function directly, you must have
prepared the variable argument list in the args argument by calling
the standard C macro va_start. Upon completion, you must similarly
call the standard C macro va_end for this list.
Output from NSLogv is serialized, in that only one thread in a process
can be doing the writing/logging described above at a time. All
attempts at writing/logging a message complete before the next thread
can begin its attempts.
The effects of NSLogv are not serialized with subsystems other than
those discussed above (such as the standard I/O package) and do not
produce side effects on those subsystems (such as causing buffered
output to be flushed, which may be undesirable). Availability
You cant declare the NSLog like that see the tutorial for NSLog its may be useful for you.
Objective-C has a number of built-in data types:
int – integer constant
float – real numbers with fractional component
double – double precision floating point number
char – a single character
short – short integer (2 bytes)
long – double short
long long – double long
BOOL – boolean
The utility function NSLog() can be used to print to the debug console in Xcode. NSLog() uses the NSString formatting services. The easiest way to create a NSString is to use the #”" notation. Inside a format string a % is a placeholder for a value. The character after the % determines the value expected, be it an int or a float and so on. If we declare an integer “int i = 5″ and want to print the value of i with NSLog() we can do it with NSLog(#”The value of i is %d”, i);
You can use %d to print the value of an int, %f for a float and double, %c for a char. For a full listing of all format specifiers supported by NSString formatting methods read through the documentation.
For More Reference Click Here
keep learning..:)
The 1st argument to NSLog is an NSString that should be a string with 0 or more format specifiers.
Use:
NSLog(#"res = %d", res);
or just:
NSLog(#"%d", res);
Have a look at the reference docs for NSLog for details.
You should specify the compiler that what kind of data type you want to print in Log,
NSLog(#"%d",res);
You should not never use NSLog(variable) directly. Instead, use NSLog(#"%d", variable) for integers or NSLog(#"%#", object) for objects.

How to pass parameter values to the custom NSLOG

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

Disallow NSLog to be used

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!

Treat using NSLog as a build error

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.

Undefined symbols for architecture i386 (yes, once again...)

I'm getting crazy about this issue!
One of errors I get is the next one:
Undefined symbols for architecture i386:
"_zipOpen", referenced from:
-[ZipArchive CreateZipFile2:] in ZipArchive.o
The peace of code when I call that method (I use objective-c++ there just in the case it matters):
#implementation ZipArchive
...
-(BOOL) CreateZipFile2:(NSString*) zipFile
{
_zipFile = zipOpen( (const char*)[zipFile UTF8String], 0 );
}
in the .h file I have
zipFile _zipFile;
and in other place:
typedef voidp zipFile;
where
typedef void *voidp;
Ok, I know it shouldn't be working probably. But it worked great before. The things changed with the new target I added for unit test.
I'll greatly thankful for any your help!
Okay, from the error
Undefined symbols for architecture i386:
"_zipOpen", referenced from:
-[ZipArchive CreateZipFile2:] in ZipArchive.o
we can tell that the prototype for zipOpen() function is declared as a C function (extern "C"), as its name isn't mangled.
So, there are basically 2 options why this error is coming up:
The zipOpen() implementation isn't being linked against your program at all (forgot to add the file/library to your build, #ifdef'd out, etc.)
The zipOpen() implementation is getting C++, not C linkage, for some reason. Maybe you've accidentally placed it inside a namespace, or the .cpp file doesn't include the header with the extern "C" declaration of the function.
We can't say which it is based on the information provided.
check wether function declaration inside a header file equals to function prototype in an implementation file

Resources