What is function signature if parameters are split by comma rather than colon when invoked? - objective-c

Read a function call like this in Apple's tutorial for OC. a bit confused about how function stringWithFormat is defined or its signature...
[NSString stringWithFormat:#"The magic number is %i", magicNumber];
A relative question is about NSLog as
NSLog(#"%i is a number", someScalarVarNumber);
Should a function call be like
[Obj FuncName:param FuncName1:param1 FuncName2:param2];

You said:
[I am] a bit confused about how function stringWithFormat is defined or its signature.
If you command-click on stringWithFormat in your code, it will take you directly to its declaration (and you can hit the "back" button to return to your code). Anyway, stringWithFormat is defined as follows:
+ (instancetype)stringWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1,2);
Those ellipses (...) indicate that it is a "variadic function", that it takes a variable length list of parameters separated by commas. This is a C programming pattern which is also incorporated into Objective-C.
In case you're wondering, that NS_FORMAT_FUNCTION is a hint to the compiler that the first parameter (1) is a printf-style format string (or more accurately, slightly richer rendition that NSString uses), and that the parameters starting at the second parameter (2) should match up with what appears in the format string. That lets the compiler check your list of parameters to see if it matches the format string.
The fact that they felt compelled to add this special logic for printf-style parameters is actually a clue to the deeper problem of variadic parameters: With the exception of printf-style case, it's hard to ensure that the parameters passed to the function match what the function was expecting.
As a result, you will generally only see variadic method declarations where the number of parameters being passed to a method is variable and that it has a printf-style format string. (Technically, you can use it in any situation with variable number of parameters, but in those situations there are generally better approaches, e.g. pass an array. In fact, if you look at Apple's newer Cocoa API, where they need variable number of parameters, they generally pass an array rather than using the variadic patterns that you'll see in some of the older API.)
So, you're right, we generally invoke a method like so:
[objectName funcName:firstValue secondParameterName:secondValue thirdParameterName:thirdValue];
But, in special cases, you can employ variadic functions.

Related

Why do objective-c array parameters not use colon notation?

Im currently learning some objective-c from the big ranch guide book. My understanding is that methods with multiple parameters use colons to separate each parameter, but when reading about creating arrays, i found this snippet of code:
NSArray *dateList = [NSArray arrayWithObjects:now, tomorrow, yesterday, nil];
This has left me confused as i thought objective-c method parameters must each be preceded by a portion of the method name along with a colon. Can anybody explain this to me?
This is an exception to the rule; this is commonly called a variadic method. If you look at the definition in NSArray.h:
+ (instancetype)arrayWithObjects:(id)firstObj, ... NS_REQUIRES_NIL_TERMINATION;
you see that you can specify an arbitrary number of parameters, as long as the last one is nil (this is called the sentinel).
This saves the developers from creating a large number of different methods having roughly the same functionality, each of which accept a different number of parameters. They did so in NSObject, where you have
- (id)performSelector:(SEL)aSelector withObject:(id)object1;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
(but no further methods).
The method only has one parameter, a variable parameter list.
Here is the Objective-C declaration from the Apple Developer website:
+ (instancetype nonnull)arrayWithObjects:(ObjectType nonnull)firstObj, ...;
There's no need for colon separation, because the object list is treated as one parameter, even thought it looks like many parameters!

What does #() mean in Objective-C?

For example,
CABasicAnimation *rotate = [CABasicAnimation animationWithKeyPath:#"transform.rotation"];
[rotate setToValue:#(M_PI)];
[rotate setDuration:0.1f];
[[aView layer] addAnimation:rotate forKey:#"myRotationAnimation"];
where M_PI is defined as a macro in math.h,
#define M_PI 3.14159265358979323846264338327950288 /* pi */
It's a pointer to an NSNumber object. It's called a boxed literal, because the mental picture is of putting a primitive value of expression inside into a "box", that is, an object.
See official documentation if in doubt. Note that pointer can be to a "real" NSNumber object or it can (theoretically, don't know whether this will work in practice) be a tagged pointer (see, e.g., my question).
Note that you can also do things like #"string" and #5, which will create constants in compile time. But you need parentheses to use something which is not a literal, e.g. #(2 + 3). Parentheses form can be used for any expression, even those that compiler cannot compute at compile-time (although if it can, it will just put an expression result into code).
NeXT and Apple Obj-C runtimes have long included a short-form way to create new strings, using the literal syntax #"a new string". Using this format saves the programmer from having to use the longer initWithString or similar methods when doing certain operations.
When using Apple LLVM compiler 4.0 or later, arrays, dictionaries, and numbers (NSArray, NSDictionary, NSNumber classes) can also be created using literal syntax instead of methods. Literal syntax uses the # symbol combined with [], {}, (), to create the classes mentioned above, respectively.
So, basically it's not only for id or NSNumber object!
thanks to wiki.
It's Shorthand writing
In Objective-C, any character, numeric or boolean literal prefixed with the '#' character will evaluate to a pointer to an NSNumber object (In this case), initialized with that value. C’s type suffixes may be used to control the size of numeric literals.
'#' is used a lot in the objective-C world. It is mostly used to avoid taking english words and making them reserved (for example, you can't have a variable called float in C/Objective-C because this is a reserved word).
Use this link To have detailed knowledge of '#' symbol.
In Modern Objective C, '#' symbol is used extensively.
What You can do with it:
calculate an expression: #(<Expression>)
wrap any value like int,bool,float,char in same way
Reasons to use:
Easy to write, Less code required
Less chances of mistakes. Compare [NSNumber numberWithInt:3] with #3.
Get rid of typecasting issues in simple cases.
It represent id Object
that you can use any expression in it or return any object.
Syntax : #(<#expression#>) it will return id object.
So in your case it will returning NSNumber object to setToValue method.

Does Objective-C have a method (or C function) returning object's format specifier for a given object?

I want to write my own method to make inspection of variables easier than I have it with NSLog - I want it to be a wrapper around the NSLog, so I need to somehow recognize a proper format specifier for any object passed to my method.
It would be nice to have a method like format_specifier_for that could do the following:
format_specifier_for(1) => %d
format_specifier_for(#1) => %#
and so on...
UPDATE:
Besides the accepted answer (it does answer the original question) there are two possible approaches to the problem:
From #Guillaume's answer: use LOG_EXPR method from http://vgable.com/blog/2010/08/19/the-most-useful-objective-c-code-ive-ever-written/.
Use overloadable attribute when defining methods as described here: How to check if a variable is an object?
I think the ideal solution could borrow from both of these options.
No, there cannot be such a function since you can always use several (in theory every one) format specifiers for the same data type. For example you can use %# to print the value of a NSString or %p to get the address in memory.
Look at that: The Most Useful Objective-C Code I've Ever Written. The author uses the C typeof operator and the Objective-C #encode directive to do something like you want...

Arguments after variadic arguments

Objective-C, or Cocoa specifically, supports variadic arguments, like for example class the method on NSString +(NSString *)stringWithFormat:(NSString *)string, .....
Now, what I would like to know is if it is possible to follow that variadic argument must be at the end of the method, or can the method continue after that?
As an example, suppose I have the variadic method (with the appropriate macro),
- (void)setObjects:(id)obj, ... NS_REQUIRES_NIL_TERMINATION;
If I want to use it at a specific index, could I do something like this,
- (void)setObjects:(id)obj, ... NS_REQUIRES_NIL_TERMINATION atIndex:(int)index;
I've been trying, and this specific example doesn't work, giving me an error message saying "Expected ';' after method prototype". Of course, I could shuffle the arguments around to make sure the variadic one is at the end, like this,
- (void)atIndex:(int)index setObjects:(id)obj, ... NS_REQUIRES_NIL_TERMINATION;
This certainly works, but to me it feels rather alien amidst the Cocoa naming conventions -- which is a problem for me.
Thank you,
Variadic arguments must be the last argument. This is because a method in Objective-C is really just an ordinary C function in disguise, and C doesn't allow any arguments after a variadic argument either.
The reason C doesn't allow it has to do with the calling convention that C supports. When you call a variadic function, the number of variadic arguments is not actually known be the function at first. Different functions can then figure it out in different ways. In Objective C, terminating a variadic argument with nil is common. The printf function figures out how many arguments it's passed based on the format string. Since the function doesn't initially know how many variadic arguments there are, it has no way of knowing the memory location of an argument after the variadic argument list.
Look up "C calling conventions" if you wish to know more.
(Some consider this limitation to be a "wart" of the C language, which is fair. However, we are stuck with it due to the need for ABI compatibility. C++ has the same issue with variadic functions.)

using objc_msgSend to call a Objective C function with named arguments

I want to add scripting support for an Objective-C project using the objc runtime. Now I face the problem, that I don't have a clue, how I should call an Objective-C method which takes several named arguments.
So for example the following objective-c call
[object foo:bar];
could be called from C with:
objc_msgSend(object, sel_getUid("foo:"), bar);
But how would I do something similar for the method call:
[object foo:var bar:var2 err:errVar];
??
Best Markus
The accepted answer is close, but it won't work properly for certain types. For example, if the method is declared to take a float as its second argument, this won't work.
To properly use objc_msgSend, you have to cast it to the the appropriate type. For example, if your method is declared as
- (void)foo:(id)foo bar:(float)bar err:(NSError **)err
then you would need to do something like this:
void (*objc_msgSendTyped)(id self, SEL _cmd, id foo, float bar, NSError**error) = (void*)objc_msgSend;
objc_msgSendTyped(self, #selector(foo:bar:err:), foo, bar, error);
Try the above case with just objc_msgSend, and log out the received arguments. You won't see the correct values in the called function. This unusual casting situation arises because objc_msgSend is not intended to be called like a normal C function. It is (and must be) implemented in assembly, and just jumps to a target C function after fiddling with a few registers. In particular, there is no consistent way to refer to any argument past the first two from within objc_msgSend.
Another case where just calling objc_msgSend straight wouldn't work is a method that returns an NSRect, say, because objc_msgSend is not used in that case, objc_msgSend_stret is. In the underlying C function for a method that returns an NSRect, the first argument is actually a pointer to an out value NSRect, and the function itself actually returns void. You must match this convention when calling because it's what the called method will assume. Further, the circumstances in which objc_msgSend_stret is used differ between architectures. There is also an objc_msgSend_fpret, which should be used for methods that return certain floating point types on certain architectures.
Now, since you're trying to do a scripting bridge thing, you probably cannot explicitly cast every case you run across, you want a general solution. All in all, this is not completely trivial, and unfortunately your code has to be specialized to each architecture you wish to target (e.g. i386, x86_64, ppc). Your best bet is probably to see how PyObjC does it. You'll also want to take a look at libffi. It's probably a good idea to understand a little bit more about how parameters are passed in C, which you can read about in the Mac OS X ABI Guide. Last, Greg Parker, who works on the objc runtime, has written a bunch of very nice posts on objc internals.
objc_msgSend(object, sel_getUid("foo:bar:err:"), var, var2, errVar);
If one of the variables is a float, you need to use #Ken's method, or cheat by a reinterpret-cast:
objc_msgSend(..., *(int*)&var, ...)
Also, if the selector returns a float, you may need to use objc_msgSend_fpret, and if it returns a struct you must use objc_msgSend_stret. If that is a call to superclass you need to use objc_msgSendSuper2.
objc_msgSend(obj, #selector(foo:bar:err:), var, var2, &errVar);