Variable Arguments (varargs) in Objective-C
Creating variable argument functions (also vararg or variadic function) in Objective-C is done the same way that it is done in C, using the stdarg.h library.
For those of us working in Cocoa, Apple has already included the import in NSObjCRuntime.h, so the only thing we have to do is start using it.
As an example, let's take a function that adds an arbitrary list of doubles stored in NSNumbers:
- Line 1:
- (NSNumber *) addValues:(int) count, ... - This is the function definition, we should see this copied exactly in the header file.
The ellipse (...) indicates that this function can accept an arbitrary number of arguments, and before that we are required to have at least one argument of any type. We must somehow know the count to keep from dereferencing an invalid pointer, but sometimes it is possible to infer that count from one of the other arguments (e.g., in
NSLogorprintfby counting the number of unescaped % symbols), or inNSMutableArrayby having the user terminate the sequence withnil.If we used that last approach here, we would change the function to:
- (NSNumber *) addValues:(NSNumber *) firstNumber, ...It could then be called as:
addValues: num1, num2, num3, nilinstead ofaddValues: 3, num1, num2, num3.
- Line 2:
va_list args; va_listis of typevoid *, so it acts as an arbitrary array of objects.- Line 3:
va_start(args, count); - Indicates that we will be using
argsto store the variable argument list, and thatcountis the last "fixed" parameter. This indicates where the compiler needs to go in memory to find the start ofargs. - Line 9:
for( int i = 0; i < count; i++ ) - A standard for loop, note that we cannot infer the size of
argsand have to explicitly know the count.If we were using a
nilterminated list, we could use:while( value = va_arg( args, NSNumber * ) )instead of Line 9 and Line 10 here.
- Line 10:
value = va_arg(args, NSNumber *); - Stores the next argument from
argsinvalue, casting it appropriately to aNSNumber *(for maximum flexibility, useid). - Line 16:
va_end(args); - Close off the variable argument list
argsafter using it.
Precaution
If you are using va_arg(args, double) (or float or another raw type like that), you may get erratic results if you attempt to pass an array of integers in, for example: addValues: 4, 4, 3, 2, 1. It would work, however, if you explicitly declared each of those variables as a double (e.g., double num1, double num2, double num3, double num4.
This is because if the compiler sees that it is a int going into a function that explicitly has a double argument it can cast it before sending it along. It doesn't know what type to use with a variable argument list, so it assumes that you know what you are doing and so it just passes the integer along to the other side.
Further Reading
-
Variable arguments in Objective-C methods on the Apple's Developer Connection, which contains an example of a
nil terminated liststdarg(3) man page
