From Objective C Programming Guide (Under the "Object Messaging" section),
Methods that take a variable number of parameters are also possible,
though they’re somewhat rare. Extra parameters are separated by commas
after the end of the method name. (Unlike colons, the commas are not
considered part of the name.) In the following example, the imaginary
makeGroup: method is passed one required parameter (group) and three
parameters that are optional:
[receiver makeGroup:group, memberOne, memberTwo, memberThree];
I tried to create such a method and it shows an error
"Expected ';' after method prototype"
when I try to declare the below function in my interface file(.h file).
- (void) printMyClass: (int) x, (int) y, (int) z;
Can anyone give sample example to create such a method like makeGroup
Thank you
You can see this link.
In your header file define the methods with three dots at the end
-(void)yourMethods:(id)string1,...;
And in you implementation file write the methods body
-(void)yourMethods:(id)string1, ...{
NSMutableArray *arguments=[[NSMutableArray alloc]initWithArray:nil];
id eachObject;
va_list argumentList;
if (string1)
{
[arguments addObject: string1];
va_start(argumentList, string1);
while ((eachObject = va_arg(argumentList, id)))
{
[arguments addObject: eachObject];
}
va_end(argumentList);
}
NSLog(#"%#",arguments);
}
Now call your method
[self yourMethods:#"ab",#"cd",#"ef",#"gf",nil];
NOTE: remember to put nil at the end
The syntax for declaring a method with a variable number of arguments is like this:
- (void) printMyClass: (int) x, ...;
One argument is always the required minimum, the others can be accessed via the va_arg function group. For the exact details, see this tutorial.
Related
In Java you can put in multiple constructors to a class that are called depending on the types and/or number of parameters that are used when an instance is constructed.
I assume that there is the equivalent in Objective C.
Can I have a polymorphic method?
I would like to build a method that acts slightly differently according to whether a string is passed or a double?
Does that sound bonkers or is it easy?
You're thinking of overloaded methods. Due to the way dynamic dispatch is implemented in Objective-C, it isn't currently possible to pass two unrelated types as arguments to the same (or same-named) method and have it understand.
In Objective-C, there are two related but distinct approaches to handling multiple kinds of input. Let's use your example of a string or a double as possible inputs. In Java, you might have:
void applyWidget(String s);
void applyWidget(double d);
And that's great, but not Objective-C. In Objective-C, you instead would use two different method names:
- (void)applyWidgetWithName: (NSString *)name;
- (void)applyWidgetWithValue: (double)value;
The same logic is in each method as in the Java version, but the distinct names let the compiler treat them as distinct methods (which they are, even in Java.) The code also becomes self-documenting: by reading it, you get an idea of what's happening even without comments. Alternatively, if you simply must have one method name, you change the parameter type to id and accept any object:
- (void)applyWidget: (id)widget;
Then pass either an NSString or an NSNumber wrapping your double. Then, in the implementation of the method, use Objective-C's introspection methods to determine how to proceed:
if ([widget isKindOfClass: [NSString class]]) {
...
} else if ([widget isKindOfClass: [NSNumber class]]) {
double d = [widget doubleValue];
...
}
This approach essentially tells callers "send anything--I'll handle it appropriately." It can be difficult to determine the behaviour of such a method without extensive documentation.
Absolutely easy:
- (id)initWithSomeObject:(id)object
{
if ([object isKindOfClass:[ClassOne class]) {
// do something
} else if ([object isKindOfClass:[ClassTwo class]) {
// do something else
} // etc.
return self;
}
yes, but objc does not have proper overloading.
so you see things like initWithDouble:, initWithBool: and so on. that's part of the reason it's a bit 'wordy' for some people's taste.
to use your example:
#interface MONClass
- (id)initWithString:(NSString *)pString;
- (id)initWithDouble:(double)pDouble;
...
but the following is an error:
- (id)initWith:(NSString *)pString;
- (id)initWith:(double)pDouble;
because the selector is the same -- the parameter/return types are omitted from the selector.
Basically Objective C does't have proper method overloading. It will support overriding only.
Suppose if you write functions like in same class,
(void) showMethod;
(void) showMethod:(int) aNumber;
This will support in Objective C.
Suppose if you write functions like,
(void) showMethod:(NSString*) aString;
(void) showMethod:(int) aNumber;
In this way the compiler gives Error because there conflicting parameter types in implementation of showMethod.
I have read in the Apple Documentation that we can use optional parameters in objective c methods call. Example from the Apple documentation :
Methods that take a variable number of parameters are also possible,
though they’re somewhat rare. Extra parameters are separated by commas
after the end of the method name. (Unlike colons, the commas are not
considered part of the name.) In the following example, the imaginary
makeGroup: method is passed one required parameter (group) and three
parameters that are optional:
[receiver makeGroup:group, memberOne, memberTwo, memberThree];
Can someone tell when to use this feature and how ? is there any example in the Apple API ?
thanks
The type of method you are describing is called a variadic method. Examples in Cocoa include +[NSArray arrayWithObjects:] and +[NSDictionary dictionaryWithObjectsAndKeys:]. You access the arguments of a variadic method (or function) using the macros defined in stdarg.h.
Here's an example of how the +[NSArray arrayWithObjects:] method might be implemented:
+ (NSArray *)arrayWithObjects:(id)firstObject, ... {
int count = 0;
va_list ap;
va_start(ap, firstObject);
id object = firstObject;
while (object) {
++count;
object = va_arg(ap, id);
}
va_end(ap);
id objects[count];
va_start(ap, firstObject);
object = firstObject;
for (int i = 0; i < count; ++i) {
objects[i] = object;
object = va_arg(ap, id);
}
va_end(ap);
return [self arrayWithObjects:objects count:count];
}
I've written a method like that once or twice. It's a bit of a pain. It works very much like parsing a command line in a C program.
I don't remember now where I found the documentation on how to do it. If I remember correctly, it uses functions va_start() and va_end().
A major down-side of that approach is that the comma-delimited list of parameters are not type checked, and don't have labels like they do in normal methods.
The main way it makes sense to use that approach is in a method like NSArray's arrayWithObjects, where you need to allow a variable-sized list of parameters of any type, or NSLog.
I would like to do something like this in my program:
[obj list error:&error];
But when I try to define the prototype/method, I get compile errors.
I've tried the following definitions:
-(void)list error:(NSError **)error;
-(void)list:() error:(NSError **)error;
nothing seems to work.
Why is the space between list and error in the method signature. If this is the prototype -
-(void) list_error:(NSError **)error;
list_error expects a pointers address to be passed to it. So, this should work.
[obj list_error:&ptr] ; // Assuming ptr is of type NSError* and is initialized.
I think, you are getting confused when to send more than one parameter to a method. Its simple. Method signature should be -
- ( return_type ) splitOne:(type) arg1 splitTwo:(type) arg2 ;
- indicates instance method. Same is the case for class method too but substitued a + instead of -. And so on the method name can be splitted.
Taking an example of fraction, to set a fraction it needs both numerator and denominator. So,
-(void) setNumerator: (int) n setDenominator: (int) d ;
And to call it -
[ obj setNumerator:10 setDenominator:20 ] ;
What is the need to split the method name ?
Normally, in C this function prototype would be -
void setFraction( int a, int b );
But when seeing the prototype, it isn't obvious whether a is numerator or denominator and is the same with b. That is the reason, why in Objective-C method name may be splitted into parts. In the above example of Objective-C, both the setNumerator and setDenominator forms the method name. And when calling, it's quite obvious to the user, the parameter being passed is what. Hope it helps to resolve your problem.
How do I declare and use small helper functions inside my normal methods ?
In on of my objective-c methods I need a function to find an item within a string
-(void) Onlookjson:(id) sender{
NSString * res = [[sender gstring] copy];
persInfoBirth.text = getKeyValue(res, #"Birth");
}
I came up with a normal C type declaration for helper function getKeyvalue like this
NSString * getKeyvalue(NSString * s, NSString * key){
NSString *trm = [[s substringFromIndex:2] substringToIndex:[s length]-3];
NSArray *list = [trm componentsSeparatedByString:#";"];
//....
NSString res;
res = [list objectAtIndex:1];
//...
return res;
}
Example input string in s:
s=#"{ Birth = "1910"; Death = "1936"; }";
Anyway I get an exception "unrecognized selector sent to instance" for any of the two first lines in the helper function
How do I declare helper functions that are just to be used internally and how to call them safely ?
regards
Martin
Is this the real code? Do you get zero errors and warnings from the compiler? You must not ignore compiler warnings and you should turn on the Static Analyser in addition to the standard warnings.
There are many things wrong with the above code, most of which are nothing todo with declaring and calling methods. There is no way the above code could compile so maybe it pasted incorrectly or something..
Anyway.. declaring and using methods. Why are using a c function? Unless you have a good reason why not use Objective-c ? If you do have a good reason to use a C function the your definition should be:-
NSString *getKeyvalue( NSString *s, NSString *key ){
...
}
note the arguments. As NSString instances reside in the heap (not on the stack) you always want to pass pointers to them.
You then need to put the declaration in the header file:-
NSString *getKeyvalue( NSString *s, NSString *key )
EDIT:
In Objective-c there is no distinction between normal methods and helper methods, there is only one kind, and you have aleray written one
- (void)onLookJson:(id)sender { .. }
Taking it apart..
All methods begin with + or –, indicating Class method or Instance method. As you are familiar with C++ i guess you know what this means.
(void) is the return type. ie this method doesn't return a value. If it did it might look like (float) or (NSString *) or (id).
onLookJson: is the method name and the method takes 1 argument. Notice that the ':' is actually part of the name. This method is never is any circumstance just 'onLookJson'. An argument must always follow the :, so a method that doesn't take any arguments must not have one.
Ex
- (NSString *)fullName { .. }
This is an instance method, for example of a Person Class, you would call it like:-
NSString *theName = [aPerson fullName];
So
a method name that takes no
arguments is like 'speak'
a method
name that takes 1 argument is like
'speakTo:'
a method name that takes 2
arguments is like 'speakTo: language:'
a method name that takes 3
arguments is like 'speakTo: language: volume:'
etc.
All that is left is to put in the argument types and names.
Your function definition:
NSString *getKeyvalue( NSString *s, NSString *key ){
would become..
- (NSString *)getValue:(NSString *)s key:(NSString *)key { .. }
again, you need to declare it in the header or you will get a compiler warning.
- (NSString *)getValue:(NSString *)s key:(NSString *)key;
Can someone explain this method declaration syntax for me? In this function, the number of rows of a UIPickerView (slot machine UI on the iPhone) is being returned. From my understanding, the Method is called 'pickerView', and returns an NSInteger.
It passes in a pointer to the UIPickerview called 'pickerView' ... first, why is the method called the same name as the parameter?
Next there is NSInteger parameter called component that tells us which component we are counting the rows for. The logic to decide which is in the body of the method.
What is 'numberOfRowsInComponent? It seems to describe the value we are returning, but it is in the middle of the parameters.
- (NSInteger) pickerView:(UIPickerView *)pickerView
numberOfRowsInComponent:(NSInteger)component
{
if (component == kStateComponent)
return [self.states count];
return[self.zips count];
}
Objective-C methods are designed to be self documenting, and they borrow from the rich tradition of Smalltalk.
I'll try to explain what you have here, -(NSInteger) pickerView:(UIPickerView*)pickerView numberOfRowsInComponent:(NSInteger)component.
- (NSInteger)
This first portion indicates that this is an Objective C instance method that returns a NSInteger object. the - (dash) indicates that this is an instance method, where a + would indicate that this is a class method. The first value in parenthesis is the return type of the method.
pickerView:
This portion is a part of the message name. The full message name in this case is pickerView:numberOfRowsInComponent:. The Objective-C runtime takes this method information and sends it to the indicated receiver. In pure C, this would look like
NSInteger pickerView(UIPickerView* pickerView, NSInteger component). However, since this is Objective-C, additional information is packed into the message name.
(UIPickerView*)pickerView
This portion is part of the input. The input here is of type UIPickerView* and has a local variable name of pickerView.
numberOfRowsInComponent:
This portion is the second part of the message name. As you can see here, message names are split up to help indicate what information you are passing to the receiver. Thus, if I were to message an object myObject with the variables foo and bar, I would type:
[myObject pickerView:foo numberOfRowsInComponent:bar];
as opposed to C++ style:
myObject.pickerView(foo, bar);.
(NSInteger)component
This is the last portion of the input. the input here is of type NSInteger and has a local variable name of component.
In Objective-C, the name of a method is composed of all of the portions of the declaration that are not arguments and types. This method's name would therefore be:
pickerView:numberOfRowsInComponent:
The method would be equivalent to a C-style function that looked as follows:
edit: (with thanks to Jarret Hardie):
NSInteger pickerViewNumberOfRowsInComponent(UIPickerView * pickerView, NSInteger component)
Adding to the previous answers, I'd just like to say that Objective-C methods (or messages if you prefer) have external and internal parameter names.
So in this case:
- (NSInteger) pickerView:(UIPickerView *)pickerView
numberOfRowsInComponent:(NSInteger)component
numberOfRowsInComponent is the external name, the one that you would use when calling this method from the outside.
And component is the internal name of the parameter, the one you use to refer to the parameter from inside of the method.
Hope that clears it up a bit.
It seems to me that Objective-C method signatures are more like sentences. Each parameter deserves a part in method's name. For instance, in C we could have a method (setPersonData) for setting some information about person:
void setPersonData( char* name, int age, float height ) {
and in Objective-C the method would be more descriptive (setPersonName:andAge:andHeight:), like
- (void) setPersonName: (char *)name andAge:(int)age andHeight:(float)height {