How to NSLog calling function - objective-c

Not the function calling the NSLog or Dlog but function that call that function.
I created a class
+(void) computeTime:(void (^)())block
{
NSDate * currentTime = [NSDate date];
block();
DLog ("Time Running is: %f", [[NSDate date] timeIntervalSinceDate:currentTime);
}
So everytime there is an operation whose time I want to measure I will put that in a block instead.
and do [Tools computeTime:^{//operation}];
However, I want to know the function that call that computeTime. How do I do so?

Two options:
The first is to abuse +[NSThread callStackSymbols] to get an array of all the symbols in the call stack and pull out the one you want. I suspect this is going to be relatively slow.
The second is to use a macro. The C preprocessor provides a nice macro called __PRETTY_FUNCTION__ which contains the name of the function all nicely formatted, and it works well for Obj-C methods as well. Instead of [Tools computeTime:^{/*operation*/}] you can either use something like [Tools computeTimeWithName:__PRETTY_FUNCTION__ block:^{/*operation*/}] or you could wrap it all up in your own macro so you can say TOOLS_COMPUTE_TIME(^{/*operation*/}):
#define TOOLS_COMPUTE_TIME(...) [Tools computeTimeWithName:__PRETTY_FUNCTION__ block:(__VA_ARGS__)]
Note, I've used a varargs-style macro because the C Preprocessor doesn't understand obj-c syntax very well, so any commas inside your block will be interpreted as separate arguments to the macro. If I defined it using TOOLS_COMPUTE_TIME(op) then the compiler would complain that the macro only takes 1 argument but it was given multiple. By using varargs the compiler doesn't care how many arguments you give it, and it will pass them all on to the __VA_ARGS__ token.

Another possible answer for someone searching for the OP's original question and adding to Kevin's first suggestion to use the call stack.
If you're looking for what called a function (method), consider the following:
NSArray *callStack = [NSThread callStackSymbols];
// Top of the stack. Current method
NSLog(#"Current method: %#", [callStack objectAtIndex:0]);
// Called by
NSLog(#"called by: %#", [callStack objectAtIndex:1]);
It is possible that the stack item looked for is further into stackArray.
Hope this helps find a bug quicker.

Related

Why can't LLDB evaluate this expression?

Neither one of these statements can be processed by LLDB... why is it unable to come up with the NSString result and print it out
expr -o -- [NSString stringWithFormat:#"%#", #"Wow this doesnt work??"]
po [NSString stringWithFormat:#"%#", #"Wow this doesnt work??"]
It seems that the expression command in lldb can generally not evaluate functions with
variable argument lists. It fails even with a simple C function:
int foo(char *msg, ...)
{
return 17;
}
(lldb) expr foo("bar")
(int) $2 = 17
(lldb) expr foo("bar", 2)
error: no matching function for call to 'foo'
note: candidate function not viable: requires 1 argument, but 2 were provided
error: 1 errors parsing expression
So this looks like a bug (or non-feature) in lldb.
This is more of academic than practical interest, but the original question and Martin's answer actually have different causes. In both cases, lldb is actually correctly refusing to call a function with more arguments than it is declared to have, but getting the actual definition wrong for different reasons.
In the first case, lldb doesn't actually have debug information for the method call [NSString stringWithFormat:format, ...]. It turns out the compiler does not emit debug information for every function your program USES, only the ones it defines. This restriction is mostly to keep the size of the debug information manageable.
So the debugger has to consult the ObjC runtime for extra type information for these kit functions. But the runtime type information doesn't encode the variable argument-ness of variable argument functions.
In the second case, what you are seeing is actually a bug in clang's debug output. It fails to emit the bit of information that tells the debugger that the function is a variable argument function.
In any case, in lldb you can work around this sort of issue by introducing declarations of commonly used functions to lldb's expression parser using the "expr-prefix" file. For instance, in Martin's case, I make a file "/tmp/expr-prefix.lldb" containing the line:
extern "C" int foo (char *msg, ...);
Then in lldb, I do:
(lldb) settings set target.expr-prefix /tmp/expr-prefix.lldb
And then you can call the function in the expression parser. A couple of caveats with this feature. This "expression prefix" file gets included in all the expression you run with the "print" command, so don't put too much stuff in there or it will slow down general expression parsing. Don't try to do things like:
#import <Cocoa/Cocoa.h>
that will be very slow and probably won't work anyway - since this depends on a whole set of #defines that the debugger doesn't know about.
But it can be very helpful if you have a few functions like this that you really need to call, but can't because we either don't know the signature or are somehow getting it wrong.
The extern "C" is required because lldb parses expressions as ObjC++.
If you want to prototype an ObjC method, you need to do it on an extension of the class you are prototyping the method for; we often have a rudimentary class def'n and the compiler doesn't like to add methods to a known class, only extensions.
I found a workaround in this article:
http://www.cimgf.com/2012/12/13/xcode-lldb-tutorial/
For example when I try to use this syntax to call method:
po [NSString stringWithFormat:#"%#", #"MyName"];
Debugger error is:
error: too many arguments to method call, expected 1, have 2
error: 1 errors parsing expression
But you can try this one:
po [[NSString alloc] initWithFormat:#"%#", #"MyName"];
Debugger message is:
$4 = 0x0a6737f0 MyName
import UIKit in debugger this worked for me
expr #import UIKit

Objective C method declaration/ calling

I'm doing a video tutorial on iPhone programming, it's a very simple calculator app. At one point I declare the following method::
- (NSString*)calculate:(NSString*)operation withNumber:(NSInteger)number
{
return nil;
}
It's not implemented yet at this point. Then I want to call the method with:
self.display.text = [self calculate:[sender currentTitle] withNumber:[self.display.text intValue]];
Xcode is giving me an error here: 'expected expression'.
What's wrong here? And what is withNumber in the method? I would understand
- (NSString*)calculate :(NSString*)operation :(NSInteger)number;
Thats a method that takes a string and an int as parameters and returns a String. I don't get what withNumber does here.
OK, for it to work, you will need to remove the unnecessary spaces :
- (NSString*)calculate:(NSString*)operation withNumber:(NSInteger)number{
...
}
and on calling the method too of course.
As to 'what is withNumber ? ' : this is the way multi-input method look like in Objective-C, the name of the method does not precede the arguments. The method is actually named calculate:withNumber: in the runtime system
I strongly recommend reading some beginner's guide
You could do - (NSString*)calculate:(NSString*)operation :(NSInteger)number and then you will have to call [self calculate:myString :myNumber]; but the vast majority of Objective-C user would not do that : the language gives you the opportunity to clarify your code and specify what arguments is what : take that opportunity.

Is there something about this method name that indicates it's asynchronous?

I've inferred what a lot of things DO in Objective-C, and I've gone through several tutorials that simply talk about the data types, but I haven't run across anything that simply explains the syntax.
For starters, what does this mean? What it does is start a thread and get data returned from a server:
- (void)apiCall:(void (^)(NSMutableArray *list))block {
Does something in that function header tell me that it is asynchronous? is that what block means?
No, block doesn't mean asynchronous, a block in Obj-C is just a bit of code that can be passed as an argument to a method.
methods that start with - are instance methods and those that start with + are class methods.
^ is a syntactic marker to denote a block.
For your first question: you would have to look at the API documentation to find out if it is asynchronous.
For more information about blocks in general, see here:
Apple Blocks Programming Guide
Let's start with your second bullet:
Class methods are declared with +, instance methods are declared with -.
The first and third are related, the parameter named block is a code block, it's a piece of code intended to be run later. Given the name of this method apiCall, I suggest this being the method run after the call is done.
It would we natural to suspect that this method will do some work on another thread and then invoke the block you supplied, but for this you'd need to check the documentation or the code.
The signature: (void (^)(NSMutableArray* list)) block describes a code block with a void return type and a NSMutableArray* list as only parameter.
An example usage of the block parameter would be:
void (^apiCallCallback)(NSMutableArray*) = ^(NSMutableArray* list) {
NSLog(#"The API returned %d items in a list", [list length]);
}
[someApiInstance apiCall:apiCallCallback];
After the API instance is done doing whatever it is suppose to do, you'll see that the log statement is printed.

Selectors in Objective-C?

First, I'm not sure I really understand what a selector is. From my understanding, it's the name of a method, and you can assign it to a class of type 'SEL' and then run methods such as respondToSelector to see if the receiver implements that method. Can someone offer up a better explanation?
Secondly, to this point, I have the following code:
NSString *thing = #"Hello, this is Craig";
SEL sel = #selector(lowercaseString:);
NSString *lower = (([thing respondsToSelector:sel]) ? #"YES" : #"NO");
NSLog (#"Responds to lowercaseString: %#", lower);
if ([thing respondsToSelector:sel]) //(lower == #"YES")
NSLog(#"lowercaseString is: %#", [thing lowercaseString]);
However, even though thing is clearly a kind of NSString, and should respond to lowercaseString, I cannot get the 'respondsToSelector' conditional to return "YES"...
You have to be very careful about the method names. In this case, the method name is just "lowercaseString", not "lowercaseString:" (note the absence of the colon). That's why you're getting NO returned, because NSString objects respond to the lowercaseString message but not the lowercaseString: message.
How do you know when to add a colon? You add a colon to the message name if you would add a colon when calling it, which happens if it takes one argument. If it takes zero arguments (as is the case with lowercaseString), then there is no colon. If it takes more than one argument, you have to add the extra argument names along with their colons, as in compare:options:range:locale:.
You can also look at the documentation and note the presence or absence of a trailing colon.
Selectors are an efficient way to reference methods directly in compiled code - the compiler is what actually assigns the value to a SEL.
Other have already covered the second part of your q, the ':' at the end matches a different signature than what you're looking for (in this case that signature doesn't exist).
That's because you want #selector(lowercaseString), not #selector(lowercaseString:). There's a subtle difference: the second one implies a parameter (note the colon at the end), but - [NSString lowercaseString] does not take a parameter.
In this case, the name of the selector is wrong. The colon here is part of the method signature; it means that the method takes one argument. I believe that you want
SEL sel = #selector(lowercaseString);
NSString's method is lowercaseString (0 arguments), not lowercaseString: (1 argument).
Don't think of the colon as part of the function name, think of it as a separator, if you don't have anything to separate (no value to go with the function) then you don't need it.
I'm not sure why but all this OO stuff seems to be foreign to Apple developers. I would strongly suggest grabbing Visual Studio Express and playing around with that too. Not because one is better than the other, just it's a good way to look at the design issues and ways of thinking.
Like
introspection = reflection
+ before functions/properties = static
- = instance level
It's always good to look at a problem in different ways and programming is the ultimate puzzle.
From my understanding of the Apple documentation, a selector represents the name of the method that you want to call. The nice thing about selectors is you can use them in cases where the exact method to be called varies. As a simple example, you can do something like:
SEL selec;
if (a == b) {
selec = #selector(method1)
}
else
{
selec = #selector(method2)
};
[self performSelector:selec];
As per apple docs:
https://developer.apple.com/library/archive/documentation/General/Conceptual/DevPedia-CocoaCore/Selector.html
A selector is the name used to select a method to execute for an object, or the unique identifier that replaces the name when the source code is compiled. A selector by itself doesn’t do anything. It simply identifies a method. The only thing that makes the selector method name different from a plain string is that the compiler makes sure that selectors are unique. What makes a selector useful is that (in conjunction with the runtime) it acts like a dynamic function pointer that, for a given name, automatically points to the implementation of a method appropriate for whichever class it’s used with. Suppose you had a selector for the method run, and classes Dog, Athlete, and ComputerSimulation (each of which implemented a method run). The selector could be used with an instance of each of the classes to invoke its run method—even though the implementation might be different for each.
Example:
(lldb) breakpoint --set selector viewDidLoad
This will set a breakpoint on all viewDidLoad implementations in your app.
So selector is kind of a global identifier for a method.

How can I dynamically create a selector at runtime with Objective-C?

I know how to create a SEL at compile time using #selector(MyMethodName:) but what I want to do is create a selector dynamically from an NSString. Is this even possible?
What I can do:
SEL selector = #selector(doWork:);
[myobj respondsToSelector:selector];
What I want to do: (pseudo code, this obviously doesn't work)
SEL selector = selectorFromString(#"doWork");
[myobj respondsToSelector:selector];
I've been searching the Apple API docs, but haven't found a way that doesn't rely on the compile-time #selector(myTarget:) syntax.
I'm not an Objective-C programmer, merely a sympathizer, but maybe NSSelectorFromString is what you need. It's mentioned explicity in the Runtime Reference that you can use it to convert a string to a selector.
According to the XCode documentation, your psuedocode basically gets it right.
It’s most efficient to assign values to SEL variables at compile time with the #selector() directive. However, in some cases, a program may need to convert a character string to a selector at runtime. This can be done with the NSSelectorFromString function:
setWidthHeight = NSSelectorFromString(aBuffer);
Edit: Bummer, too slow. :P
I'd have to say that it's a little more complicated than the previous respondents' answers might suggest... if you indeed really want to create a selector... not just "call one" that you "have laying around"...
You need to create a function pointer that will be called by your "new" method.. so for a method like [self theMethod:(id)methodArg];, you'd write...
void (^impBlock)(id,id) = ^(id _self, id methodArg) {
[_self doSomethingWith:methodArg];
};
and then you need to generate the IMP block dynamically, this time, passing, "self", the SEL, and any arguments...
void(*impFunct)(id, SEL, id) = (void*) imp_implementationWithBlock(impBlock);
and add it to your class, along with an accurate method signature for the whole sucker (in this case "v#:#", void return, object caller, object argument)
class_addMethod(self.class, #selector(theMethod:), (IMP)impFunct, "v#:#");
You can see some good examples of this kind of runtime shenanigans, in one of my repos, here.
I know this has been answered for long ago, but still I wanna share. This can be done using sel_registerName too.
The example code in the question can be rewritten like this:
SEL selector = sel_registerName("doWork:");
[myobj respondsToSelector:selector];