Define custom NSAssert that includes line, class and general formatting - ios

As the title reads, how could I define a custom NSAssert which would include the line, class, and formatting as per my NSLog below:
#define NSLog(__FORMAT__, ...) NSLog((#"%#: " __FORMAT__), NSStringFromClass([self class]), ##__VA_ARGS__)
The problem is that NSAssert has a BOOL value first before the rest of the arguments are taken under account. I can't seem to find a solution without taking out the arguments and separating them.
Is there a better way to solve this?
Long story short, I'm looking for something like this:
#define DebugAssert(__VA_ARGS__[0], #"%#: %#", NSStringFromClass([self class]), __VA_ARGS__[1])

The NSAssert macro is defined like this:
#define NSAssert(condition, desc, ...) /* the implementation */
So, the condition is already a separate parameter from the format string and the variable argument list. There should be no problem doing something similar to what you did for NSLog:
#define MyAssert(condition, desc, ...) \
NSAssert(condition, (#"%#: " desc), NSStringFromClass([self class]), ##__VA_ARGS__)

Related

How to replace NSLog with DLog with common file?

My current project does not contain prefix.pch file.I added the following code on Constants.h file
#ifdef DEBUG
# define DLog(fmt, ...) NSLog((#"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
#else
# define DLog(...)
#endif
Then I replaced my NSLog in my viewcontroller like the following:
DLog(#“Replaced”)
But I always got the error like Implicit declaration of function 'DLog' is invalid in C99 on my this specific view controller .
How to resolve this issue?

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

Using DebugLog() instead of NSLog()

i want to use DebugLog() to print values instead of NSLog(). I believe DebugLog() is more efficient. But i am not able to use it in my project(doesn't appear in prompt). I believe we have to set something in Build settings for that. Does anyone have any idea about this?
Thanks.
DebugLog() is not a supported method in objetice-c, if you want to implement it yourself, do something like this:
#ifdef DEBUG
#define DebugLog(s, ...) NSLog(s, ##__VA_ARGS__)
#else
#define DebugLog(s, ...)
#endif
Taken from here:
DebugLog Format string is not a string literal
#ifdef DEBUG
# define DLog(fmt, ...) NSLog((#"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#else
# define DLog(...)
#endif
To call NSLog only for the debug build:
#ifdef DEBUG
NSLog("Debugging");
//or any other statement
#endif
(This will be called only when the build configuration is 'debug' in your scheme)

Custom NSLog Method ( Variadic )

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.

Is there a way to tell what line of code generates log output without using breakpoints and stepping in Xcode (iOS)?

I have the following log outputs in Xcode:
2013-05-20 17:23:19.901 MyApp[2408:303] invalid pixel format
2013-05-20 17:23:19.901 MyApp[2408:303] invalid context
The problem is I don't know what line of code is generating these errors. I've tried walking through but it's extremely tedious considering the complexity of this part of my app. Is there a quick and simple way to track down the line of code that is outputting these?
Yes, there is a way to do what you are asking. Simply add the following to your prefix header YourAppName-Prefix.pch.
#define NSLog(fmt, ...) NSLog((#"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
That will override NSLog with a custom NSLog that will print like this:
2013-05-20 21:11:10.407 YourAppName[46526:c07] -[JFDepthView initWithGestureRecognizer:] [Line 81] JFDepthView Initialized!
It should also work for 3rd party libraries you've added to your project.
From "C" documentation, Standard Predefined Macros - The C Preprocessor:
__FILE__ and __LINE__ are useful in generating an error message
NSLog(#"Line: %d", __LINE__);

Resources