Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

jca69

macrumors newbie
Original poster
Jun 13, 2013
24
0
Vancouver, BC
This will seem a dumb question, but as I've spent too much time doing ABAP, I'm afraid my C/Objective-C skills are pretty rusty.

I'm not sure if I'll ever produce any interesting app on the App Store, but anyways, I'm kind of having fun playing around with Xcode, Objective-C and the iPhone.

So here's the thing. I'm following Paul Hegarty's lessons on iTunes U and while trying to solve the exercises/enhancements to his programs, I came across the following conundrum.

In one class I have the following method:

Code:
-(NSString *)doStuff {

    NSString *result;
    
    result = nil;
    ...
    if (...) {
        ...
        result = [NSString stringWithFormat:@"You won %d points!", points];
    } else {
        result = [NSString stringWithFormat:@"You lost %d points!", points];
    }
    ...
    return result; 
}

In another class that calls the one above:

Code:
@property (weak, nonatomic) IBOutlet UILabel *infoLabel;

- (IBAction)cardSelected:(UIButton *)sender {
    NSString *result;

    result = [self.myGame doStuff];
    self.infoLabel.text = result;  // or self.infoLabel.text = [self.myGame... ]; for short
    [self refreshUI];

}

This works, result in cardSelected receives whatever is put in the string in doStuff.
However, when I first tried getting the result in cardSelected not as myGame return value but as an argument, result is always null. The code would be the following:

Code:
-(void)doStuff:(NSString *)result {
    
    result = nil;
    ...
    if (...) {
        ...
        result = [NSString stringWithFormat:@"You won %d points!", points];
    } else {
        result = [NSString stringWithFormat:@"You lost %d points!", points];
    }
    ...
}

And the call looked something like this:

Code:
@property (weak, nonatomic) IBOutlet UILabel *infoLabel;

- (IBAction)cardSelected:(UIButton *)sender {
    NSString *result;

    [self.myGame doStuff:result];
    self.resultLabel.text = result;
    [self refreshUI];

}

If the string is allocated in doStuff in both cases, why is not passed to the argument in cardSelected?
Thanks
 
Your first approach is attempting to assign the value by reference, but you haven't written the syntax correctly. To do so:

Code:
-(void)doStuff:(NSString **)result {
     ...
    if (...) {
        ...
        *result = [NSString stringWithFormat:@"You won %d points!", points];
    } else {
        *result = [NSString stringWithFormat:@"You lost %d points!", points];
    }
    …
}

Then call doStuff like this:

Code:
    [self.myGame doStuff:&result];

However, this entire approach is wrong. There's no point in assigning a value by reference for a simple function that only needs to return a string.
 
Your first approach is attempting to assign the value by reference, but you haven't written the syntax correctly. To do so:

Code:
-(void)doStuff:(NSString **)result { ...

...

Right, the double indirection!! Thanks, and I agree, in this case/language, it doesn't make sense to return the result passing the reference in the argument.
 
Looking at your code, it looks like there is a syntax error bolded below:

Code:
@property (weak, nonatomic) IBOutlet UILabel *infoLabel;

- (IBAction)cardSelected:(UIButton *)sender {
    NSString *result;

    [B][self.myGame doStuff:result];[/B]
    self.resultLabel.text = result;
    [self refreshUI];

}

In your definition of doStuff, there is no declaration for data to be passed into the function, which is where you would then use a colon :)) following the function name to do so. The line "[self.myGame doStuff:result];" is trying to send result, but doStuff is not coded to receive any data.

I think what you meant to do, was execute doStuff and have it return it's data to result. In that case, the following code is more appropriate:

Code:
@property (weak, nonatomic) IBOutlet UILabel *infoLabel;

- (IBAction)cardSelected:(UIButton *)sender {
    NSString *result;

    [B]result = [NSString stringWithFormat: @"%@", [self.myGame doStuff]];[/B]
    self.resultLabel.text = result;
    [self refreshUI];

}
 
Looking at your code, it looks like there is a syntax error bolded below:

Code:
@property (weak, nonatomic) IBOutlet UILabel *infoLabel;

- (IBAction)cardSelected:(UIButton *)sender {
    NSString *result;

    [B][self.myGame doStuff:result];[/B]
    self.resultLabel.text = result;
    [self refreshUI];

}

In your definition of doStuff, there is no declaration for data to be passed into the function, which is where you would then use a colon :)) following the function name to do so. The line "[self.myGame doStuff:result];" is trying to send result, but doStuff is not coded to receive any data.

I think what you meant to do, was execute doStuff and have it return it's data to result. In that case, the following code is more appropriate:

Code:
@property (weak, nonatomic) IBOutlet UILabel *infoLabel;

- (IBAction)cardSelected:(UIButton *)sender {
    NSString *result;

    [B]result = [NSString stringWithFormat: @"%@", [self.myGame doStuff]];[/B]
    self.resultLabel.text = result;
    [self refreshUI];

}

Actually, OP was just trying to pass result by reference so that it was modified within the doStuff method
 
Right, the double indirection!! Thanks, and I agree, in this case/language, it doesn't make sense to return the result passing the reference in the argument.


C, and hence Objective C, always passes parameters by value. There is no direct support for passing values by reference.

I did quite a bit of Pascal programming on Mac before OSX. Pascal lets you declare parameters as either by value or by reference as part of of the function definition. No such thing in C/Objective-C however.

As the other poster said, if you want to pass an object by reference, you need to use pointer-to-pointer syntax.

Note that this is generally frowned upon. It makes the code hard to follow. There are rare cases where you need this syntax (a method that needs to return multiple objects) but there is almost always a better way to handle it (e.g. returning a dictionary that contains the multiple result objects)
 
Looking at your code, it looks like there is a syntax error bolded below:

No, no syntax error, both versions of the code compiled, maybe I missed something in the code while posting it here. It's just that, like waterskier2007 said, I was trying to pass result by reference without much success, a very un-C practice, according to what I'm reading here.

I remember that feature from Pascal. And in ABAP, by default everything is passed by reference, so I guess I'm "speaking" Objective-C with a thick accent :D
 
Last edited:
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.