views:

392

answers:

2

I want to swap where player is pointing to here. I'm doing it wrong for sure, but can't figure out why. I've also tried using (Player **)player in the signature and &player when I called it. Any ideas?

- (void)handleResult:(Result)result forPlayer:(Player *)player inLineup:(Lineup *)lineup
{
    switch (result)
    {
        case ResultSub:
        {
            Player *sub = [lineup.substitutes objectAtIndex:0];
            player = sub;
            return;
            break;
        }
    }
}
+3  A: 

You were on track. You need to have Player ** as the type, call it with an &, and then use a * when you do the assignment:

*player = sub; 

That should do it. Watch your memory management.

Carl Norum
Beat me by 6 seconds! `:)`
e.James
Cool, thank you, trying it out. Getting some other errors though, Probably more of my handiwork.
rob5408
Downvote because....?
Carl Norum
Because it is against standard coding practices and it is only half the answer; passing stuff by ref like that would require deep understanding on calling side. For example, I'd bet that the OP would next stumble over how to, say, pass by-ref with the eventual assignment going to an ivar.
bbum
But, yeah... down vote removed.
bbum
Up vote for answering my question, but it was sort of like asking how to shoot myself in the foot. thanks!
rob5408
+13  A: 

While Carl is correct, that is almost assuredly exactly what you don't want to do.

Namely, it is exceptionally rare in Cocoa or iOS to pass values by reference with the purpose of updating them remotely. Beyond being fragile and error prone, it is also generally a violation of encapsulation, a fundamental OO principal.

Given context, it sounds like you are doing some kind of a baseball sort of app? Assuming so.

Thus, you have a Lineup class whose instances represent a lineup within a Team (maybe even a Team class whose instances represent individual teams) with each team managing a lineup of Player instances.

So, you might have something like:

@interface Lineup:NSObject
- (BOOL) substitutePlayer: (Player *) sub;
@end

And you might call it like this:

- (void)handleResult:(Result)result
           forPlayer:(Player *)player
            inLineup:(Lineup *)lineup
{
    ... handle substituion ...
    [lineup substitutePlayer: player];
}

And you might implement the substitutePlayer: as:

- (BOOL) substitutePlayer: (Player *) playerToReplace;
{
    NSUInteger *index = [self.players indexOfObject: playerToReplace];
    [self.players replaceObjectAtIndex: index withObject: [self.substitutes objectAtIndex: 0]];
    [self.substitues removeObjectAtIndex: 0];

    return YES;
}

By doing this, you avoid the goofy (Player **) stuff and you encapsulate all the lineup manipulation inside of the lineup class. If you were ever to need to specialize the lineup -- say, -substitutePlayer: should use the last guy in self.substitutes -- you could subclass Lineup and do so.

End result; much cleaner OO design, much easier to maintain code, and much less fragile patterns.

(Fixed some stupid bugs due to coding in SO's edit window.)

bbum
Upvote. In the last 6 or so years I don't think I've ever seen a "pass by reference for updating" in obj-c, except for NSError.
kubi
@kubi NSStream also comes to mind. There's probably a few others out there.
Cory Kilger
Pass by reference is also used in Cocoa for multiple returns, with the "get" idiom:- (void)getLeftSprocket: (Sprocket **)outLeftSprocket andRightSprocket (Sprocket **)outRightSprocket withWidget: (Widget *)aWidget;Or, in an actual API:+[NSStream getStreamsToHost:port:inputStream:outputStream:];(Return types for "get" methods vary from coder to coder. If nothing else, BOOL is pretty common because it's an immediate indicator of the success/failure of the message dispatch.)
Jonathan Grynspan
The "get" idiom is pretty rare in practice. NSStream is definitely one of the very very few "get" style APIs that do exist, though.
bbum
Hi bbum, thanks, let me give it a go. It's actually pretty close to my original code. However once outside of the handleResult method, the player was repointing back to the original. That's what sent me down the ref path.Actually, maybe I'm showing the wrong code. The first thing I do is set Player *player = [lineup.players objectAtIndex:i]; After that line, does player point to index i (which points to an object) or does it point directly to the object at index i?
rob5408
Oh and it's a soccer app. Easy, you just have to simulate a score of nil nil for every match ;)
rob5408
So I've tried it and whats happening is that the substitution happens fine, but outside handleResult, my player object still points to the subbed out player. Any time I try to point player to the subbed in player inside handleResult or substitutePlayer, it always reverts back to the subbed out player once it leaves the function. I can do something like player = [away.players objectAtIndex:i]; after every call to handleResult, but its a bit tedious.
rob5408
That makes sense; if you want the player to change outside of that method you need to change it. Doing it by reference is, again, oddly inconsistent with the rest of the design patterns used. Making the call after -handleResult: is the right thing to do.
bbum