Print the name of the calling function to the debug log - objective-c

Objective-C's runtime seems to be rather robust, so I was wondering if there's a way to log the name of the function that called the current function (for debugging purposes).
My situation is that a bunch of things assign to a property, and rather than set a breakpoint and examine the call stack each time, I'd like to just NSLog the name of the function that is setting the property, along with the new value.
So is it possible to get access to the call stack at runtime?

Try this:
#include <execinfo.h>
void *addr[2];
int nframes = backtrace(addr, sizeof(addr)/sizeof(*addr));
if (nframes > 1) {
char **syms = backtrace_symbols(addr, nframes);
NSLog(#"%s: caller: %s", __func__, syms[1]);
free(syms);
} else {
NSLog(#"%s: *** Failed to generate backtrace.", __func__);
}

Great Question. Combining Jeremy's Answer above and what we always use for our debugging, you'll get a nice string like this:
NSArray *syms = [NSThread callStackSymbols];
if ([syms count] > 1) {
NSLog(#"<%# %p> %# - caller: %# ", [self class], self, NSStringFromSelector(_cmd),[syms objectAtIndex:1]);
} else {
NSLog(#"<%# %p> %#", [self class], self, NSStringFromSelector(_cmd));
}

There is no facility for getting the sender. Or, at least, nothing centric to Objective-C.
There are a couple of alternatives, though.
First, you could use GDB commands. Go to the GDB console and do something like:
comm 1
bt
po argName
cont
Alternatively, you could use dtrace. This is hard. Or you could use Instruments which makes dtrace somewhat easier.
Or you could use the backtrace() function. See the backtrace man page (x-man-page://backtrace).

There is a C macro called __PRETTY_FUNCTION__ that will return a C-String with the name of the current function. If you would like to convert that to an NSString for easily printing to NSLog, you can create a macro with
#define NSSTRING_PRETTY_FUNCTION [NSString stringWithCString:__PRETTY_FUNCTION__ encoding:NSASCIIStringEncoding]
I use it all the time in my projects.

Related

Xcode / Objective-c - How to find the callers of a given method programmatically

In xcode I am able to find the callers of a given method using the button in the picture.
Is it possible to do at runtime?
Something like:
-(NSArray *)getCallersOfFoo {
// is it possible to find the callers of the method foo?
}
-(void)foo {...}
Not exactly an answer, but it might help. This methods will give you a printout of stack or of caller in debug area. You can modify them of course to use the values as you please.
Code is kind of 'stolen' but i have no reference to where from.
#define SHOW_STACK NSLog(#"%#",[NSThread callStackSymbols])
#define SHOW_CALLER \
do { \
NSArray *syms = [NSThread callStackSymbols]; \
if ([syms count] > 1) { \
NSLog(#"<%# %p> %# - caller: %# ", [self class], self, NSStringFromSelector(_cmd),[syms objectAtIndex:1]); \
} else { \
NSLog(#"<%# %p> %#", [self class], self, NSStringFromSelector(_cmd)); \
} \
} while(0)
EDIT: you would probably want something like this:
NSString *caller = nil;
NSArray *syms = [NSThread callStackSymbols];
if (syms.count > 1)
{
caller = syms[1];
}
if (caller.length)
{
NSLog(#"%s called by %#",
__PRETTY_FUNCTION__,
caller);
}
There is another Q&A here on SO you might find very useful.
The short answer: no.
The long answer: well, you can mess around with the call stack, and then put in some more effort to make use of what you get. But it's most probably not what you're looking for.
Generally, the method should not care at all how it's called.

Macro that logs the actual types of method arguments

Let's say this is my init method
- (id)initWithClient:(id <Client>)client
andDataStorage:(DataStorage *)storage
{
if (self = [super init])
{
self.client = client;
self.storage = storage;
}
return self;
}
Then I want to write a macro that somehow logs the parameters passed to a method, by wrapping the parameter with a defined macro. Is this possible in any way?
The problem is at runtime it's not possible to find out the type of a parameter passed to a method. So I'm trying to find a hack around it, and do it at compile time.
// somehow achieve this, and log the value inside the marco
#define INJECT(x) NSLog(#"%#", x)
- (id)initWithClient:(INJECT(id <Client>))client
andDataStorage:(INJECT(DataStorage *))storage
{
}
expected log in console:
id <Client>
DataStorage *
At the risk of running into what appear to be crossed wires in the comments: you can get the parameter types passed to a method at runtime.
E.g.
NSMethodSignature *signature =
[class methodSignatureForSelector:#selector(someSelector:)];
for(int argument = 2; argument < signature.numberOfArguments; argument++)
{
const char *argumentType = [signature getArgumentTypeAtIndex:argument];
// this is where it gets a bit messy...
if(!strcmp(argumentType, #encode(int))) NSLog(#"an integer");
if(!strcmp(argumentType, #encode(float))) NSLog(#"a float");
// ... etc, etc, etc ...
}
For any passed objects, use [object class] since all objects look the same at the runtime level — think of e.g. NSArray -addObject:; the runtime knows an object type will be passed in but it could be any object type.
See Apple's documentation on Type Encodings for information on what's going on there with those #encodes.
Whilst not an answer to the question as such. I would not recommend doing what you are asking about. I've seen far to much code where people have logged every single method call and argument (horribly over-complicated Java Enterprise stuff). The result has always been obscenely large logs that tell you next to nothing because of the amount of work it takes to find what you are after.
My recommendation would be that logging is important, but you should do targeted logging that clearing shows the state of relevant data at specific points which are important to understanding the flow.
Like others, I'm not sure what you are really after, or whether it is a good idea/design etc. But I wonder whether you are approaching the problem the wrong way. So let's take a look and maybe it will help you. From what I see you:
Want to find some way of obtaining the declared types of method parameters, in the form of strings, at runtime.
You are trying to tackle this by adding macros to the source. This tells me that you are not trying to do this for methods in a binary library that you are dynamically loading, but to methods in source you are compiling and are prepared to modify to achieve your goal.
Looked at that way, what is the problem? If you are prepared to add macros to your source why not simply add data declarations that contain the information you want - a mapping from a selector to an order list of parameter types as strings.
Is the issue that you want to extract the information in some automated way and were intending adding your macros by some automated process?
You can arrange for an Xcode project to run a source file through some other program by changing the file extension. Apple provide examples of using this to pre-process strings files - the files are fed through a Ruby script which produces a strings file which Xcode then handles as usual. Will that address your needs? Could you write a script/application (doesn't need to be in Ruby) which could add the information you need "on the fly" - take source in, produce modified source out which Xcode then compiles as usual? Note that the Clang compiler itself is designed to be called as a library so you can even use it to help you parse your source to extract the information you are after.
If none of those approaches suit consider that the debugger knows the correct types at runtime, and it gets those from the symbol information generated for it. There are library functions provided to help reader debugger information, so you should be able to write code which uses the same information the debugger does.
Hope those ideas help you, though I'm still not clear what you are trying or whether it makes sense!
due to objC being dynamically typed, all classes have the type id. The information about the declared types is erased. They are merely hints for the developer and to enable the compiler to do some type checking (again purely for the dev's benefit)
So while #encode works for 'primates' and structs and stuff, for classes all is equal... as there are not really object types for runtime
'Solution': Store the class names of method argumentsin a map manually and then COMBINE that info with #encode;s info to log the stuff.
working sample:
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
NSDictionary *DDParamsMap(void);
NSDictionary *DDParamsMap() {
static NSDictionary *dict = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//TODO
//add all methods that are have objc classes passed
//add the classes or NSNull
dict = #{#"Test_initWithArray:data:number:": #[NSArray.class, NSData.class, NSNull.null]};
});
return dict;
}
void DDLogParamsOf(Class class, SEL sel);
void DDLogParamsOf(Class class, SEL sel) {
//
//try internal lookup first (so we get class names
//
NSString *className = #(class_getName(class));
NSString *methodName = NSStringFromSelector(sel);
NSString *key = [NSString stringWithFormat:#"%#_%#", className, methodName];
NSArray *types = DDParamsMap()[key];
//
// loop
//
NSMethodSignature *signature = [class instanceMethodSignatureForSelector:sel];
if(!signature) {
signature = [class methodSignatureForSelector:sel];
}
//if the array doesnt have the right number of values, screw it!
if(types.count != signature.numberOfArguments - 2) {
types = nil;
}
for(int argument = 2; argument < signature.numberOfArguments; argument++) {
id type = types[argument - 2];
if(type && ![type isKindOfClass:[NSNull class]]) {
NSLog(#"class is %#", type);
}
else {
const char *argumentType = [signature getArgumentTypeAtIndex:argument];
// this is where it gets a bit messy...
if(!strcmp(argumentType, #encode(int))) NSLog(#"an integer");
if(!strcmp(argumentType, #encode(float))) NSLog(#"a float");
if(!strcmp(argumentType, #encode(id))) NSLog(#"it is a class");
// ... etc, etc, etc ...
}
}
}
#define LogParams() DDLogParamsOf(self.class, _cmd);
#interface Test : NSObject
+ (void)testMethofWithFloat:(float)f;
- (id)initWithArray:(NSArray*)a
data:(NSData*)d
number:(int)i;
#end
#implementation Test
+ (void)testMethofWithFloat:(float)f {
LogParams();
}
- (id)initWithArray:(NSArray*)a
data:(NSData*)d
number:(int)i
{
LogParams();
return nil;
}
#end
int main(int argc, char *argv[]) {
#autoreleasepool {
[Test testMethofWithFloat:3.0f];
Test *t = [[Test alloc] initWithArray:#[] data:[NSMutableData data] number:1];
t = nil;
}
}

Objective C - caller Object of a method [duplicate]

Example: When my method -fooBar gets called, I want it to log in the console which other method of which other class called it.
Right now, I only know how to log the method name of fooBar itself and it's class, with this:
_cmd
[self class]
Is this possible to figure out?
In fully optimized code, there is no 100% surefire way to determine the caller to a certain method. The compiler may employ a tail call optimization whereas the compiler effectively re-uses the caller's stack frame for the callee.
To see an example of this, set a breakpoint on any given method using gdb and look at the backtrace. Note that you don't see objc_msgSend() before every method call. That is because objc_msgSend() does a tail call to each method's implementation.
While you could compile your application non-optimized, you would need non-optimized versions of all of the system libraries to avoid just this one problem.
And this is just but one problem; in effect, you are asking "how do I re-invent CrashTracer or gdb?". A very hard problem upon which careers are made. Unless you want "debugging tools" to be your career, I would recommend against going down this road.
What question are you really trying to answer?
How about this:
NSString *sourceString = [[NSThread callStackSymbols] objectAtIndex:1];
NSCharacterSet *separatorSet = [NSCharacterSet characterSetWithCharactersInString:#" -[]+?.,"];
NSMutableArray *array = [NSMutableArray arrayWithArray:[sourceString componentsSeparatedByCharactersInSet:separatorSet]];
[array removeObject:#""];
NSLog(#"Class caller = %#", [array objectAtIndex:3]);
NSLog(#"Method caller = %#", [array objectAtIndex:4]);
Credits to the original author, intropedro.
It's not possible in the general case without actually walking the stack. There's not even a guarantee that another object send the message that called the method. For example, it could be called from a block in a signal handler.
NSLog(#"Show stack trace: %#", [NSThread callStackSymbols]);
See backtrace(3).
User the below method
Pass index for which you want to display method and pass -1 if you want to display full stack of method
+(void) methodAtIndex:(int)index{
void* callstack[128];
int frames = backtrace(callstack, 128);
char** strs = backtrace_symbols(callstack, frames);
if (index == -1) {
for (int i = 0; i < frames; ++i) {
printf("%s\n", strs[i]);
}
}
else {
if (index < frames) {
printf("%s\n", strs[index]);
}
}
free(strs);
}
This information can be obtained using DTrace.
Make a macro that adds the __FUNCTION__ to the function name to the function call. This macro will then call your function with an extra parameter of a char* to the target function.
I was trying to catch who, how and when changes window's size and did some handwork:
- (void)logWindowWidth:(NSString *)whoCalls {
NSLog(#"%#", whoCalls);
NSLog(#"self.window.size.width %f", self.window.size.width);
}
-(void)someMethod {
[self logWindowWidth:#"someMethod - before"];
...
[self logWindowWidth:#"someMethod - after"];
}
-(void)anotherMethod {
[self logWindowWidth:#"anotherMethod - before"];
...
[self logWindowWidth:#"anotherMethod - after"];
}

Why doesn't this rudimentary Objective C-block code work?

I am trying to understand the fundamentals of blocks. I wrote this simple test:
NSString *(^print_block) () = ^ (NSString *returned_string){
return #"this block worked!";
};
NSLog(#"%#", print_block);
I expected console output to be "this block worked!", but instead I get a big flood of error numbers and etc,, ending with:
terminate called throwing an exception
What up?
Edit: the answer has been suggested to use:
NSLog (#"%#", print_block());
But that doesn't work either. The program terminates at the start of the block definition, with the console saying only (lldb) and Xcode putting a little green arrow at the block definition. The arrow reads:
Thread 1: EXC_BAD_ACCESS (code=1, address=0x5f646e71)
I've tried something else that doesn't work:
NSString *(^print_block) () = ^ (NSString *returned_string){
NSString *return_me = #"this block worked!";
return return_me;
};
NSLog(#"%#", print_block);
But at least this doesn't terminate the program. It runs fine. But the console output is still wrong:
<__NSGlobalBlock__: 0x5a58>
Vatev's comment is right on. When you write:
NSLog(#"%#", print_block);
you're passing the block print_block as the argument for the format string in the log statement. You're trying to print the block. This probably results in [print_block description] being called. I don't know if blocks implement a -description method, but if not then you'll get an unrecognized selector exception.
Also, the way you've declared the block is incorrect. You don't need to include the return value in the parameter list.
The following code works as you expect:
NSString *(^print_block)() = ^{
return #"this block worked!";
};
NSLog(#"%#", print_block());

Is using respondsToSelector: good style?

Is it "better style" to send a message and hope the object responds, or to check to see if it responds to a selector and have some sort of fallback if it doesn't.
For example:
- (NSString *)stringForObjectValue:(id)obj {
if ([obj respondsToSelector:#selector(intValue)]) {
NSString *roman = [self formatRomanNumber:[obj intValue] resultSoFar:#""];
return roman;
} else {
return [NSString stringWithFormat:#"can't format a %#", [obj class]];
}
}
vs.
- (NSString *)stringForObjectValue:(id)obj {
NSString *roman = format_roman(#"", [obj intValue]);
return roman;
}
(the example is from a NSNumberFormatter subclass...but it could be from a NSObjectFormatter subclass...)
If you're not 100% sure that all instances that come to your (stringForObjectValue) function respond to selector then you must perform that check to avoid crashes in runtime.
How to handle the cases when obj does not respond to intValue selector may depend on particular context where your method is used. For example you may return nil object from method in that case so you can easily see that something went wrong
If you don't know the exact type then using respondsToSelector: is definitely good style, because you risk an exception otherwise. And it's so important that there's a name for this technique: Duck Typing.