Get method arguments dynamically in Objective-C - objective-c

I'm new to Objective-C.
[deskCalc add: 55];
NSLog(#"After adding %f to accumulator, accumulator is :%f", 55, [deskCalc accumulator]);
Some context; this is a snippet from a simple calculator program that looks fairly similar to the one found in the first post in this thread. As its name suggests, the add method add's the argument to an integer variable "accumulator", which stores the final value. Finally, the accumulator method simply returns the variable.
My question is: Rather than having to manually type the argument (55 in this case) after the string, is it possible to have code that references whichever argument is passed on to the add method (dynamically)?
I've seen other questions (such as this and this) that at least sound somewhat simlar to a noob like myself, but I haven't been able to join the dots and figure out a solution.

In general, you can't retrieve the argument from a previous message send expression.
One simple solution is to put the value in a variable and refer to it in both places:
float addend = 55;
[deskCalc add: addend];
NSLog(#"After adding %f to accumulator, accumulator is :%f", addend, [deskCalc accumulator]);
IF the deskCalc object were specifically coded to keep track of the last operation and its operands, you could ask it for the value. Here I hypothesize the existence of a lastAddend property on the class and use that:
[deskCalc add: 55];
NSLog(#"After adding %f to accumulator, accumulator is :%f", [deskCalc lastAddend], [deskCalc accumulator]);

Related

Variable number of method parameters in Objective C - Need an example

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.

objective-c: return value

I'm reading Stephen Kochan's "Programming in Objective-C" (I'm n0000b). Everything has been obvious to me until exercise 4-8.
It asks me to modify methods, in an "Accumulator" class created earlier in the chapter, to "return" the value of the accumulator when one of the math methods is used (basically it's a calculator). I took this originally to mean that I want the program to display the result whenever one of the methods is used (+, -, *, /), so I set it up to do so, so each line displays the cumulative result rather than just the final result:
[deskCalc setAccumulator: 0.0];
[deskCalc add: 200.]; //the result is displayed
[deskCalc divide: 100.0]; //the result is displayed
[deskCalc subtract: 1.0]; //the result is displayed
[deskCalc multiply: 5]; //the result is displayed
NSLog (#"The result is %g", [deskCalc accumulator]);
But after looking up other people's solutions, it appears that "returning the value of the Accumulator" means something different.
Can someone describe to me what returning a value means, and what purpose it serves? I have looked through the previous chapter a few times but it is still unclear to me how this will make the program behave differently.
Thanks!
-Andrew
The calculation methods you have in your accumulator class probably look something like this at the moment:
- (void)add:(float)aFloat {
result += aFloat;
NSLog(#"%f", result);
}
This method, in its current state, returns nothing (void). It outputs the current total on screen only. That's nice for an exercise, but in real-world programs, a calculation result will probably not be very useful if it's displayed on screen. Instead, you probably will want to do something else with the result, so you want the method to return it. For example, the NSString class has a method length. This method would not be very useful if it were to print the length of the string on screen. Instead, it returns the length, so the program can do something useful with this value (like checking that the string has the correct length):
int length = [tweet length];
if (length > 140) {
// display a useful error message
...
} else {
// tweet it :)
...
}
To modify your calculator methods to return something, you will (a) have to change the method signature to have a return value, and (b) to actually return this value.
In the method signature, simply change the return type to something other than void. In your example, the correct type would probably be float (or whatever type the calculator is using internally for its current result).
- (float)add:(float)aFloat {
...
}
To actually return the current value, you would add a return statement add the end of your method (before the closing })
return result;
(this assumes that result is the instance variable containing the current calculation result).
They are asking you to modify your add, divide, substract methods to return the value of the accumulator upon completion of the performed operation. My guess is that your original add/divide/etc methods defined a (void) return value, meaning they don't return any value from the function call. As a result you could not perform a execution similar to the following:
NSLog(#"Updated value: %g", [deskCalc substract: 1.0]);
Returning a value from a function means that not only could the function perform some type of operation, but it also returns some sort of value to the calling code. The purpose of returning a value is that it allows you to separate your code into logical components, allows for code reuse and increases maintainability of your code.
Here's an example of how it would be useful: let's say you need to calculate the square root of a number. Your code don't care how the square root is calculated, you just want the number. By using a function which takes in a value, calculates its square root and then returns the calculated value to the calling code, your code can worry about what it needs to do with the returned value of the function without having to worry about the logic itself.
Here is an example of a function which returns a NSString:
- (NSString *) getAString {
return #"String being returned";
}
Here is how you would use that function:
NSString *myString = [someObject getAString];
I hope this helps you along in your learning process.

How to determine whether a #selector wants a parameter?

The scenario presents itself where I have an object that stores an outside #selector for later use. By design, I would like to be able to add two kinds of selectors. The simple one, without parameters, like [object add:#selector(doSomething)], and the more complex one, with one parameter, like [object add:#selector(doSomething:)] (mind the colon). Let's say the selector is stored in a variable SEL mySelector.
In the execution, I need to decide between [anotherObject performSelector:mySelector] or [anotherObject performSelector:mySelector withObject:userInfo]].
The way I implemented this decision, is by providing a BOOL flag that redundantly stores whether the performance should be with or without the extra parameter. Yet although I can't find this in the docs, I have the feeling that I should also be able to ask the selector something like -(BOOL)needsParameter. I know, for example, that UIGestureRecognizer's addTarget:action: somehow makes this distinction automatically.
Could someone point me in the right direction?
You can use the NSMethodSignature class for that. For instance,
SEL mySelector = …;
NSMethodSignature *msig = [anotherObject methodSignatureForSelector:mySelector];
if (msig != nil) {
NSUInteger nargs = [msig numberOfArguments];
if (nargs == 2) { // 0 non-hidden arguments
}
else if (nargs == 3) { // 1 non-hidden argument
}
else {
}
}
Alternatively, you could use NSStringFromSelector() to get the string representation of mySelector and count the number of occurrences of the colon character.

Passing arguments by value or by reference in objective C

I'm kind of new with objective c and I'm trying to pass an argument by reference but is behaving like it were a value. Do you know why this doesn't work?
This is the function:
- (void) checkRedColorText:(UILabel *)labelToChange {
NSComparisonResult startLaterThanEnd = [startDate compare:endDate];
if (startLaterThanEnd == NSOrderedDescending){
labelToChange.textColor = [UIColor redColor];
}
else{
labelToChange.textColor = [UIColor blackColor];
}
}
And this is the call:
UILabel *startHourLabel; // This is properly initialized in other part of the code
[self checkRedColorText:startHourLabel];
Thanks for your help
Objective-C only support passing parameters by value. The problem here has probably been fixed already (Since this question is more than a year old) but I need to clarify some things regarding arguments and Objective-C.
Objective-C is a strict superset of C which means that everything C does, Obj-C does it too.
By having a quick look at Wikipedia, you can see that Function parameters are always passed by value
Objective-C is no different. What's happening here is that whenever we are passing an object to a function (In this case a UILabel *), we pass the value contained at the pointer's address.
Whatever you do, it will always be the value of what you are passing. If you want to pass the value of the reference you would have to pass it a **object (Like often seen when passing NSError).
This is the same thing with scalars, they are passed by value, hence you can modify the value of the variable you received in your method and that won't change the value of the original variable that you passed to the function.
Here's an example to ease the understanding:
- (void)parentFunction {
int i = 0;
[self modifyValueOfPassedArgument:i];
//i == 0 still!
}
- (void)modifyValueOfPassedArgument:(NSInteger)j {
//j == 0! but j is a copied variable. It is _NOT_ i
j = 23;
//j now == 23, but this hasn't changed the value of i.
}
If you wanted to be able to modify i, you would have to pass the value of the reference by doing the following:
- (void)parentFunction {
int i = 0; //Stack allocated. Kept it that way for sake of simplicity
[self modifyValueOfPassedReference:&i];
//i == 23!
}
- (void)modifyValueOfPassedReference:(NSInteger *)j {
//j == 0, and this points to i! We can modify i from here.
*j = 23;
//j now == 23, and i also == 23!
}
Objective-C, like Java, only has pass-by-value. Like Java, objects are always accessed through pointers. "objects" are never values directly, hence you never assign or pass an object. You are passing an object pointer by value. But that does not seem to be the issue -- you are trying to modify the object pointed to by the pointer, which is perfectly allowed and has nothing to do with pass-by-value vs. pass-by-reference. I don't see any problem with your code.
In objective-c, there is no way to pass objects by value (unless you explicitly copy it, but that's another story). Poke around your code -- are you sure checkRedColorText: is called? What about [startDate compare:endDate], does it ever not equal NSOrderedDescending? Is labelToChange nil?
Did you edit out code between this line
UILabel *startHourLabel;
and this line?
[self checkRedColorText:startHourLabel];
If not, the problem is that you're re-declaring your startHourLabel variable, so you're losing any sort of initialization that was there previously. You should be getting a compiler error here.
Here are the possibilities for why this doesn't work:
the label you pass in to checkRedColorText is not the one you think it is.
the comparison result is always coming out the same way.
... actually, there is no 3.
You claim you initialised startHourLabel elsewhere, but, if it is a label from a nib file, you should not be initialising it at all. It should be declared as an IBOutlet and connected to the label in the nib with interface builder.
If it is not a label in the nib i.e. you are deliberately creating it programmatically, you need to check the address of the label you initialise and check the address of the label passed in to checkRedColorText. Either NSLog its address at initialisation and in checkRedColorText or inspect it with the debugger.

What does it mean to return an object in a method?

I still cannot understand what does it mean to return an object in a method. What would its value mean?
If I have something like this:
-(ClassName *) methodName: (int) arg {
return arg;
}
I can't understand how an object can be returned through a method as the above. If someone can help me understand.
Thanks.
You would return an object by returning an object. For example, you could ignore the argument:
- (ClassName *)methodName:(int)arg {
return [[[ClassName alloc] init] autorelease];
}
You could turn the int into an object:
- (NSNumber *)methodName:(int)arg {
return [NSNumber numberWithInt:arg];
}
You could use the argument in some calculation to determine some property of the object returned. You could process the argument and return an object indicating the status of the calculation. And so on and so on. There's a practically unlimited range of ways you could return an object from a method. All it requires is that some object be created or accessed and then returned.
The above method returns a pointer to arg which is of type ClassName*.
I assume explaining the question would assume basic knowledge of how functions are called, how passed values are pushed on stack before function call and how return values is returned from a function.
In this specific case your arg variable is part of a class, meaning that it is stored in memory that is part of the object. When you return pointer to it you are pointing to a specific area of memory within the object.
Another option is to return copy of the value. It would mean make a copy and return it.
The difference is that if you return pointer to objects internal variable that object state could be modified from outside.
If you return copy that copy can be modified and the original object will not change.
Not sure if that helps, but you are asking about very basic software development topic which assumes some background knowledge.
Maybe specify what exactly you are looking for?
Think of methods like they are functions in math. In math, sin(180) is equal to 0. sin is the method, 180 is the argument and 0 is the return value of the method. An example of sin in objective-c might go like this:
-(double) sin:(double)angleInDegrees;
{
double sinValue;
//calculate the return value here and store it in sinValue.
//for example, if angleInDegrees is 180, then set sinValue to 0
return sinValue;
}
Returning objects is exactly the same. Look at this example:
-(NSString*) sayHelloTo:(NSString*)name;
{
return [NSString stringWithFormat:#"Hello %#!", name];
}
If I were to write it like a math function, then sayHelloTo(#"Tom") is equal to #"Hello Tom!". The only difference is that #"Hello Tom!" is an NSString object, not a double.