PDA

View Full Version : recursive method question




dashiell
Jul 31, 2011, 07:41 AM
Hi,

This is a 2 part question for a match 3 game I'm making.

part 1:

I want to run another method to remove the nodes not flagged connected after the following method flags nodes connected. The recursion does end, it's not stuck in an infinite loop.

If I add a breakpoint after calling the flagConnectedWithIndex method (or NSLog), it is never reached.

part 2:

How can I free the memory allocated for the surroundingIndices pointer?


-(void) flagConnectedWithIndex:(int)index
{

NSMutableArray *surroundingIndices = [self getSurroundingIndices:index];

for(NSNumber *num in surroundingIndices) {
int indexNum = [num intValue];

id obj = [arrayEnemyTargets_ objectAtIndex:indexNum];
if(obj != [NSNull null]) {
Enemytarget *t = obj;
if(!t.isDead && !t.connected) {

t.connected = YES;
//[t setOpacity:128];

[self flagConnectedWithIndex:t.index];

}
}
}
}


Thanks a lot!



jiminaus
Jul 31, 2011, 04:18 PM
part 1:

I want to run another method to remove the nodes not flagged connected after the following method flags nodes connected. The recursion does end, it's not stuck in an infinite loop.

If I add a breakpoint after calling the flagConnectedWithIndex method (or NSLog), it is never reached.

Put a breakpoint at the top of the method and step through it. What does execute? If surroundingIndices is too big for this to be practical, add lots of NSLog calls so you get running commentary on what parts of the method are executing and why.


part 2:

How can I free the memory allocated for the surroundingIndices pointer?

Send it release after the for loop?

dashiell
Jul 31, 2011, 04:23 PM
Thanks for your reply, Jiminaus.

Everything is executed within this. There is no point where it fails. The only problem is anything called after this method is not called.

I can't release surroundingIndices after the for loop, as it will break recursion.

jiminaus
Jul 31, 2011, 04:30 PM
Everything is executed within this. There is no point where it fails. The only problem is anything called after this method is not called.

Assuming your not doing anything bizarre like setjmp/longjmp or stack hacking, the only reason I see for that would be if an exception is causing the stack to unwind.

I can't release surroundingIndices after the for loop, as it will break recursion.

What do you mean by "it will break recursion"?

chown33
Jul 31, 2011, 05:30 PM
part 1:

I want to run another method to remove the nodes not flagged connected after the following method flags nodes connected. The recursion does end, it's not stuck in an infinite loop.

If I add a breakpoint after calling the flagConnectedWithIndex method (or NSLog), it is never reached.


How do you know the recursion ends? What evidence do you have that the recursion ends? You may believe it ends, but belief and evidence are two different things.

The fact that it's not hitting the breakpoint seems like evidence that the recursion does NOT end. Or at least it doesn't end normally. If it did, then the breakpoint or NSLog() should be hit, and you'd have evidence that it ends.

What happens if you put an NSLog() or breakpoint before the for loop? Does it hit that every time? At what point do those logs or breakpoints stop? If they ever stop, then that's evidence that the recursion has stopped. But if the breakpoint or NSLog() after the loop is never hit, then the likely explanation is that you have an exception, perhaps due to stack overflow.


Post the code for getSurroundingIndices: . Maybe it's not returning.


part 2:

How can I free the memory allocated for the surroundingIndices pointer?

If getSurroundingIndices: is following the Cocoa naming rule for ownership of returned objects, then its returned NSMutableArray will not be owned by the calling method (flagConnectedWithIndex:). That means getSurroundingIndices: will already have called -autorelease, or done something else to account for the memory of the returned array. Which then means that flagConnectedWithIndex: should do nothing to free the memory for its surroundingIndices object.

If you're not following the Cocoa naming rule, you should be.
http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/MemoryMgmt/

dashiell
Jul 31, 2011, 06:50 PM
Thanks chown & jiminaus.

If I autorelease the indices array in getSurroundingIndices on return, it breaks.

I tryed logging as you posted, thanks.


-(NSMutableArray*)getSurroundingIndices:(int)index
{
NSMutableArray *indices = [NSMutableArray arrayWithCapacity:6];

int bottomLeft,bottomRight,topLeft,topRight, left, right;

if(index/Grid_Num_H %2 == 0) {

if(index %Grid_Num_H != 0) {
left = index - 1;
bottomLeft = index - Grid_Num_H -1;
topLeft = index + Grid_Num_H -1;

[indices addObject:[NSNumber numberWithInt:left]];
[indices addObject:[NSNumber numberWithInt:bottomLeft]];
[indices addObject:[NSNumber numberWithInt:topLeft]];

}

right = index +1;
bottomRight = index - Grid_Num_H;
topRight = index + Grid_Num_H;
if(index % Grid_Num_H != 8)
[indices addObject:[NSNumber numberWithInt:right]];
[indices addObject:[NSNumber numberWithInt:bottomRight]];
[indices addObject:[NSNumber numberWithInt:topRight]];


}

else {
bottomLeft = index - Grid_Num_H;
left = index - 1;
topLeft = index + Grid_Num_H;

[indices addObject:[NSNumber numberWithInt:bottomLeft]];
if(index % Grid_Num_H != 0)
[indices addObject:[NSNumber numberWithInt:left]];
[indices addObject:[NSNumber numberWithInt:topLeft]];

if(index % Grid_Num_H != 8) {
right = index + 1;
bottomRight = index - Grid_Num_H +1;
topRight = index + Grid_Num_H + 1;

[indices addObject:[NSNumber numberWithInt:right]];
[indices addObject:[NSNumber numberWithInt:bottomRight]];
[indices addObject:[NSNumber numberWithInt:topRight]];
}
}
return indices;
}

jiminaus
Jul 31, 2011, 07:02 PM
Because you used a convenience constructor (arrayWithCapacity:) instead of alloc/initWithCapacity, you don't own the array. Therefore you should send neither release nor autorelease, unless of course you retain it at some point.

dashiell
Jul 31, 2011, 08:09 PM
Because you used a convenience constructor (arrayWithCapacity:) instead of alloc/initWithCapacity, you don't own the array. Therefore you should send neither release nor autorelease, unless of course you retain it at some point.

-Ah, thank you.

Luke Redpath
Aug 1, 2011, 06:14 AM
Put a breakpoint at the top of the method and step through it. What does execute? If surroundingIndices is too big for this to be practical, add lots of NSLog calls so you get running commentary on what parts of the method are executing and why.


If you are using Xcode 4, this isn't necessary. Add your breakpoint, then right click on it and select Edit Breakpoint. You can change the breakpoint to simply log and continue; no need to litter your code with NSLog statements.



Send it release after the for loop?

Wait, how is getSurroundingIndices: defined? It probably returns an autoreleased array and doesn't need releasing.

jiminaus
Aug 1, 2011, 07:23 AM
If you are using Xcode 4, this isn't necessary. Add your breakpoint, then right click on it and select Edit Breakpoint. You can change the breakpoint to simply log and continue; no need to litter your code with NSLog statements.

Nice tip.

Wait, how is getSurroundingIndices: defined? It probably returns an autoreleased array and doesn't need releasing.

Yes, we determined that. I had confused the significance of a -get<property> accessor verses a -property accessor. I was think it was ownership verses non-ownership. But it's result passed by reference verses result passed by value. Now, I'm certain the OP isn't aware of this subtly and has just incorrectly named the method.