Objective C - caller Object of a method [duplicate] - objective-c

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"];
}

Related

ObjC: Put logic within a variable, and queue that variable in an array... daydreaming?

I'm trying to translate the following JS code to ObjC; It basically defines a function and store it in an array for later execution:
var logic = function() {
me.removeNode(node);
}
this.queue.push(logic);
My ObjC port contains the method: -(void)removeNode:(AbstractNode*)node and I'm stuck... I would like to just queue a call to this method using the specified "node" argument...
edit: I'm reading about selectors. It's still blurry, but might help. Somehow. Or not?
Is it even possible, or will I need to find a workaround :-) ?
Thanks!
Solution to this thanks to the community:
// Queue declaration
NSMutableArray *IRQ = [[NSMutableArray array] retain];
// Add logic to the queue for delayed execution:
[IRQ addObject:^{ NSLog(#"thanks for the help!"); } ];
// Call later
for (int i = 0; i < [IRQ count]; i++){
void (^delayedCall)(void) = [IRQ objectAtIndex:i];
delayedCall();
}
Use a block:
[queue addObject:^{
[me removeNode:node];
}];
Here's a short introduction to blocks. They are the Objective-C equivalent of anonymous functions.
I believe you should be able to do this with function pointers. If your call backs all take the same type and set of arguments you should be able to write generic code for invoking
You can also use the NSInvocation class.

ObjC: BAD ACCESS when call blocks ^{} in later functions?

Following this discussion, I've encountered a bad access issue;
A loop has several steps: a, b, c, ... x, y, z:
-(void)cycle:(float)delta{
[self stepA]
[self stepB]
// etc.
[self stepZ]
}
At some point, step x does the following:
// IRQ is an NSMutableArray
// Self is a reference to the engine running the cycles
[IRQ addObject:^{ NSLog(#"hello! %#", self); } ];
Later, step z is to process all "delayed" calls:
for (int i = 0; i < [IRQ count]; i++){
void (^delayedCall)(void) = [IRQ objectAtIndex:i];
delayedCall();
}
[IRQ removeAllObjects];
Result: EXEC_BAD_ACCESS
Now, if step x only adds a plain string with no object reference like follows, step Z works fine:
[IRQ addObject:^{ NSLog(#"hello!"); } ];
Last observation, if a same step both adds blocks to the queue AND iterates over the queue to execute the blocks, then no problem occurs.
Like the reference to an object gets "lost" as the step: method is left?
I don't understand much in this area and will need more help!
edit:
James, just tried the following to avoid that reference cyle:
NSString *userName = #"James";
[IRQ addObject:^{ NSLog(#"hello %#", userName); } ];
and it also happens. How would your solution apply to this?
Thanks in advance!
When you create a block with the ^{} syntax, it's created on the stack. To persist the block for a long period of time (beyond the scope of the function that creates it), you must copy the block into the heap:
void (^ myBlock)(void) = ^ {
// your block code is here.
};
[IRQ addObject:[[myBlock copy] autorelease]];
If using ARC, skip the -autorelease message.
The problem is that block objects are created on the stack. You need to copy blocks to the heap when you expect them to be used after the scope in which they were declared is destroyed, and if the block is not copied for you.
Here you pass an object "down the stack" to a method that is not aware of blocks. Replace
[IRQ addObject:^{ NSLog(#"hello! %#", self); } ];
with
[IRQ addObject:[^{ NSLog(#"hello! %#", self); } copy]];
and the EXC_BAD_ACCESS at this point will go away.
In most cases though, you do not need to copy the block! A couple of examples:
If you return a block from a method ("up the stack"), ARC will automatically copy it.
If you call a method that does not keep the block, the block does not need to be copied, because it stays in scope. Example: the block passed to -[NSArray sortedArrayUsingComparator:].
If you call a method that uses the block later, the method should take the responsible for copying the block, otherwise each and every caller would need to copy the block. All methods/functions from Apple's libraries that I am aware of follow that pattern. Example: the completion block passed to +[UIView animateWithDuration:options:animations:completion:].
It seems the object you pass in.. In your examples: self and userName are being prematurely deallocated. This isn't the behaviour I expect from blocks. As in my previous answer, I expected the problem to be because of too much retention!
As a test, could you try:
NSString *userName = [#"James" retain];
[IRQ addObject:^{ NSLog(#"hello %#", userName); } ];
This would be a memory leak, but it would help indicate if the object is being deallocated.
This is caused by a "retain cycle" where the block is retaining self and self is retaining the block.
Try this:
__block typeof(self) blockSafeSelfReference = self;
[IRQ addObject:^{ NSLog(#"hello! %#", blockSafeSelfReference); } ];
If using ARC, use __unsafe_unretained instead of __block

How to call my method in cocoa, self doesn't work

Working on a program that will record some things from the webcam when a user presses physical buttons connected to the mac via phidgets. Have call methods on other places in my app simply doing [self method: input], but on one place it doesn't work. What could be wrong?
This is the method i want to run if i get inputchange in my program.
Also i do -(void)reportButton2:(NSInteger)inputVal:(NSInteger)inputInd; in my .h file.
-(void)reportButton2:(NSInteger)inputVal:(NSInteger)inputInd {
//NSLog(#"phidget för port = %%d med signal %%d", ind, val);
if(inputVal == 1)
{
NSError* error;
NSFileManager* deleteMgr = [NSFileManager defaultManager];
NSString* path = #"/Users/Shared/tempFile.mov";
[deleteMgr removeItemAtPath:path error:&error];
[mCaptureMovieFileOutput recordToOutputFileURL:[NSURL fileURLWithPath:#"/Users/Shared/tempFile.mov"]];
}
else if(inputVal == 0)
{
[mCaptureMovieFileOutput recordToOutputFileURL:nil];
}
}
The code below give me result if imput from the buttons change. Here i just can't seem to call reportbutton2.
If i try to use [self reportButton2..] in gives me "Use of undeclared identifier 'self'"
int gotInputChange(CPhidgetInterfaceKitHandle phid, void *context, int ind, int val) {
what to do here?
return 0;
}
The problem is that gotInputChange is a C function not a Objective C method and so has no udea what self is as it does not belong to a class.
for [self reportButton2... = to work it needs to be a method in your class
I usually put something like this at the top of callbacks like gotInputChange:
MyObject *self = (id)context;
Then I can use self throughout the function as if it were a method.
The other thing being in a function makes harder is asserting conditions. The regular assertion macros, such as NSAssert and NSParameterAssert, require both of the implicit arguments to every method (self is one of them) to exist. In a C function, you must use NSCAssert, NSCParameterAssert, etc. instead.
You can also use your delegate.
SomeNameAppDelegate *delegate = (SomeNameAppDelegate *)[[NSApplication sharedApplication] delegate];
[delegate yourMethodName];
It works like in example if your target method in AppDelegate class. But when you have an access to delegate, you can create a pointers to necessary classes and use them over delegate.
Quickest but not soo nice way is to make your Class a singleton and access it from the gotInputChange function.
Okay thanks! Din't have any clue that it was C would never have solved it by myself. Did some googeling and this one did the trick for me.
[(id)context performSelectorOnMainThread:#selector(reportButton2:)withObject:[NSArray arrayWithObjects:[NSNumber numberWithInt:ind], [NSNumber numberWithInt:val], nil] waitUntilDone:NO];

Method with an array of inputs

I want to have a method where I can put as many arguments as I need like the NSArray:
- (id)initWithObjects:(id)firstObj, ... NS_REQUIRES_NIL_TERMINATION;
I can then use:
NSArray *array = [[NSArray alloc] initWithObjects:obj1, obj2, ob3, nil];
I can add as many objects as I want as long as I add 'nil' at the end to tell it I'm done.
My question is how would I know how many arguments were given, and how would I go through them one at a time?
- (void)yourMethod:(id) firstObject, ...
{
id eachObject;
va_list argumentList;
if (firstObject)
{
// do something with firstObject. Remember, it is not part of the variable argument list
[self addObject: firstObject];
va_start(argumentList, firstObject); // scan for arguments after firstObject.
while (eachObject = va_arg(argumentList, id)) // get rest of the objects until nil is found
{
// do something with each object
}
va_end(argumentList);
}
}
I think what you're talking about is implementing a variadic method. This should help: Variable arguments in Objective-C methods
I haven't had experience with these variadic methods (as they're called), but there's some Cocoa functionality to deal with it.
From Apple's Technical Q&A QA1405 (code snippet):
- (void)appendObjects:(id)firstObject, ...
{
id eachObject;
va_list argumentList;
if (firstObject) // The first argument isn't part of the varargs list,
{ // so we'll handle it separately.
[self addObject:firstObject];
va_start(argumentList, firstObject); // Start scanning for arguments after firstObject.
while ((eachObject = va_arg(argumentList, id))) // As many times as we can get an argument of type "id"
{
[self addObject:eachObject]; // that isn't nil, add it to self's contents.
}
va_end(argumentList);
}
}
Copied from http://developer.apple.com/library/mac/#qa/qa2005/qa1405.html
I would try this: http://www.numbergrinder.com/node/35
Apple provides access in their libraries for convenience. The way to know how many elements you have is by iterating over the list until you hit nil.
What I would recommend, however, if you want to pass a variable number of arguments into some method you're writing, just pass an NSArray and iterate over that array.
Hope this helps!

Print the name of the calling function to the debug log

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.