This question already has answers here:
Is the 1st argument of an Objective C variadic function mandatory?
(3 answers)
Closed 8 years ago.
Typically, methods (and functions) that use variadic arguments seem to have it as the 2nd parameter like so:
- (void)setContentsWithFormat:(NSString *)formatString, ...;
Is it possible to declare this method so the variadic arguments are the first and sole parameter to this method? If so, what's the syntax for it?
I tried: - (void)setContentsWithArguments:(...) but that didn't work.
No, it isn't possible. The first parameter is effectively the reference point which tells the variadic functions how to access the additional parameters. Hence the va_start function takes the first method parameter (or, rather, the parameter just before the veridic) as its parameter:
- (void)doSomethingWithStrings:(NSString *)firstString, ...
{
va_list vList;
va_start(vList, firstString);
... blah blah
}
It seems that GCC supported it with the syntax:
- (void)setContentsWithArguments:...
But LLVM does not.
Related
I have a pure C function, to which I would like to pass a block (a closure?). As per Apple, the block should always be the last parameter to a function.
double pureCfunctionWithABlockParameter( int ignore, double ignore2, void (^myVoidBlockWithoutParameters)(void) ) {
myVoidBlockWithoutParameters(); /
return 0.0;
}
Next is the Objective C code to call the C function:
- (void) testBlockFunctionality {
declare and define the block:
void (^myBlock1)(void) ;
myBlock1=^(void){ NSLog(#"myBlock1 just logs this message to the console");};
Attempt to invoke the block directly, without parentheses. This doesn't work. Xcode warns result is unused. Block's message is NOT logged to console.
myBlock1;
Now attempt to invoke the block directly, this time with parentheses. This works as intended. No Xcode warnings, and the block's message IS logged to console.
myBlock1();
Now call the function, passing the block as parameter, WITHOUT parentheses. This works as intended, but the syntax is not consistent with the previous invocation of the block.
double someNumber;
someNumber= pureCfunctionWithABlockParameter(0, 1, myBlock1 );
Now call the function, again passing the block as a parameter, this time WITH parentheses. This doesn't work, it won't even compile, as Xcode gives a: "Passing 'void' to parameter of incompatible type 'void (^)(void)'" message.
someNumber= pureCfunctionWithABlockParameter(0, 1, myBlock1());
At the end of it all, I am actually looking to have a block defined that gets passed an int parameter, like this:
void(^block)(int)
But I cannot progress to that because of what I think is a syntax issue.
I've looked in Apple's Block Programming Topics, and even K&R C, but no luck.
The question has caused some confusion, because blocks (in the question's sense) are not a feature of standard C. Apple added them as an extension to its C and C++ compilers when it added them to Objective C, but they are not a C thing outside the Apple ecosystem. I confess that I've no experience actually using them, but as far as I can tell from the docs, such as these, the syntax was chosen so as to be the same for C, C++, and Objective C. Indeed, some sources claim that details of the syntax were chosen specifically to avoid the possibility of conflict with C++.
From a C perspective, accepting a block as a parameter and calling a block received that way are thoroughly analogous to accepting a function pointer and calling the pointed-to function, respectively. Your example C function appears to be correct.
Similar applies to declaring and and working with blocks, in all three languages -- it is analogous to declaring and working with function pointers. I am confident that this was an intentional design consideration. Thus
void (^myBlock1)(void) ;
indeed declares myBlock1 as a block taking no parameters and returning nothing, but does not define its value. Having elsewhere set a valid value for it, such as is demonstrated in the question, the OP observes
Attempt to invoke the block directly, without parentheses. This
doesn't work. Xcode warns result is unused. Block's message is NOT
logged to console.
myBlock1;
, as indeed should be expected. That's a statement expression evaluating to the value of the block, not to the result of executing the block. It is analogous to
int myInt = 1;
myInt; // specifically, analogous to this
To execute a block, one provides a postfix argument list in parentheses (even if the list is empty), just like when calling a function through a function pointer:
Now attempt to invoke the block directly, this time with parentheses.
This works as intended. No Xcode warnings, and the block's message IS
logged to console.
myBlock1();
The presence or absence of an argument list is what disambiguates whether one is accessing the block's value or calling it.
The confusion is about passing a block to a function (or method):
Now call the function, passing the block as parameter, WITHOUT
parentheses. This works as intended, but the syntax is not consistent
with the previous invocation of the block.
double someNumber;
someNumber= pureCfunctionWithABlockParameter(0, 1, myBlock1 );
Yet, contrary to the assertion in the question, that syntax as completely consistent, both internally consistent with other aspects of block syntax and usage, and consistent with analogous function pointer syntax and usage. That passes the block to the function, identifying the block by its name. The block itself is passed, not the result of executing it, because no argument list for it is provided.
At the end of it all, I am actually looking to have a block defined
that gets passed an int parameter, like this:
void (^block)(int)
But I cannot progress to that because of what I think is a syntax
issue.
A C function accepting and using such a block might look like this
void pass_2(void (^do_something)(int)) {
do_something(2);
}
Given variable block declared as shown above, and assigned a valid block as its value, that function could be called like so:
pass_2(block);
Just as we recognize that function pass_2 is called by the presence of an argument list, we recognize that the value of variable block is passed as an argument -- not called -- by the absence of an argument list.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 9 years ago.
Improve this question
When is it appropriate to write a method with a variable number of arguments (like NSString's +stringWithFormat:)?
A brief search of variadic methods from Apple seems to include only two classes: when creating a data structure (NSArray's +arrayWithObjects:, NSSet's +setWithObjects:), or when formatting a string (NSString's +stringWithFormat:, NSPredicate's +predicateWithFormat:).
Apple's documentation for variadic methods includes an example that is subtly different from the previously mentioned data structure methods, but still in the same camp.
Is it appropriate to use variadic methods in any other context? Does Apple?
When is it appropriate to write a method with a variable number of arguments (like NSString's +stringWithFormat:)?
This method uses a printf-like attribute which checks the format string against the additional parameters. You should always add an attribute to your methods/functions when using a format string.
A brief search of variadic methods from Apple seems to include only two classes: when creating a data structure (NSArray's +arrayWithObjects:, NSSet's +setWithObjects:), or when formatting a string (NSString's +stringWithFormat:, NSPredicate's +predicateWithFormat:).
This form uses a nil sentinel. It's actually a bit relaxed because an unexpected nil can silently truncate your parameters without error or warning. As an example, the (new-ish) Objective-C Literals do not use this form; they use implementations which also take count as a parameter, and it is an error to pass nil elements.
Is it appropriate to use variadic methods in any other context?
It's used in many places in C, and there are also variadic macros. Generally, you should look for alternatives because variadics are a less safe API.
One place I will use them is if I need to wrap an API. In that case, I only forward the parameters to the API which takes the va_list.
You can find safer alternatives for almost every use case, especially since the introduction of blocks.
To my knowledge, Cocoa's uses of functions with variable number of arguments is limited to the two categories that you have mentioned. For example, NSLog and NSAssert can be considered functions from the second category, because it formats a string.
However, functions with variable number of arguments can be very useful when in other situations.
For example, you can define an API for evaluating expressions that looks like this:
NSNumber *res = [Evaluator evalExpression:#"%1 + %2 * %3", #10, #20, #5];
// returns #110
Another example could be an API for composing XML, like this:
MyXmlTree *tree = [MyXmlTree addElementWithTag:#"root" andChildren:
[MyXmlTree elementWithTag:#"hello"]
, [MyXmlTree elementWithTag:#"world"]
, nil];
The second example is a more complex case of composing a data structure (i.e. composing a tree, rather than defining a linear structure).
Is it possible create an IMP where the number of parameters matches the selector for the instance method being resolved?
I could use an 'if' statement and a finite number of parameters (say between 0 and 10), but is it possible to have eg IMP_implementationWithBlock with va_args ?
You can't create a function at runtime in C; the number of parameters has to be known at compile time.
You can use a variadic function to pretend that you have a function with any number of arguments, (I've included this usage in a recent project) but this may not be portable and is probably Undefined Behavior.
If you need to move arguments between functions where the signatures and arguments are not known until runtime, you almost certainly want to look into libffi.
Mike Ash has a few really useful posts about it: http://www.mikeash.com/pyblog/?tag=libffi
that's where I got started and learned most of what I know about it.
I am trying to define a protocol method without adding parameters but couldn't find the correct syntax.
Here is the definition (it has a syntax error)
- (void)cameraOverlayView:(CameraOverlayView *)cameraOverlay didTakePhoto;
I don't want to pass any values with the second parameter. My aim is only to signal that something happened to the delegate instance.
How should I write the definition?
Your the second part of the method is not formatted correctly:
- (void)cameraOverlayView:(CameraOverlayView *)cameraOverlay didTakePhoto;
Because of the space, it's expecting a parameter. Instead, work the didTakePhoto part into the method name, like:
- (void)cameraOverlayViewDidTakePhoto:(CameraOverlayView *)cameraOverlay;
- (void)cameraOverlayViewDidTakePhoto:(CameraOverlayView *)cameraOverlay;
basically in objective c you can't have method name parts dangling after parameters...
so:
illegal:
-(void)methodWith:(int)theInt forMyMom;
normal:
-(void)methodForMyMomWithInt:(int)theInt;
legal but strange
-(void)method:(int)theInt :(int)theOtherInt;
with the selector: #selector(method::)
This is an issue of Objective-C convention. You could rewrite it as:
- (void)cameraOverlayView:(CameraOverlayView *)cameraOverlayViewDidTakePhoto;
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Method overloading in Objective-C?
Is method overloading not possible.
I have two functions with the same name.
When declared like the below i'm etting errors.
-(RS232Msg*)CreateMessage:(REMOTE_MESSAGE_ID) nMessageNumber;
-(RS232Msg*)CreateMessage:(const uint8_t*) szMessageName;
when declared -(RS232Msg*)CreateMessage:(const uint8_t*) szMessageName; i'm not getting any errors.
I also have two functions as the same name with different return type and argument.But its working fine and there is no error in its declaration.
Why is it so?
No, method overloading is not possible in C, and therefore not possible in Objective-C (since Objective-C is a superset of C). If you'd like to use those two methods, you'll have to change their names. I would suggest the following:
- (RS232Msg *)createMessageWithMessageID:(REMOTE_MESSAGE_ID)nMessageNumber;
- (RS232Msg *)createMessageWithName:(const uint8_t*)szMessageName;