Living object is released by GC

Discussion in 'iOS Programming' started by annguyen, Oct 20, 2008.

  1. annguyen macrumors newbie

    Joined:
    Oct 2, 2008
    #1
    My custom UIImageView object is held by:
    - an array
    - an NSMutableArray
    - an NSArray of the parent view (it happens by [parrentView addSubView:myObj]; )

    So my object's retainCount is 3. But when I call to release the NSMutableArray, my object got released as well? :( As normal behaviour, it should be decreased its retainCount to 2.
    And this issue occurs intermittently.

    Does anyone got similar issue like mine?
    :apple:
     
  2. Luke Redpath macrumors 6502a

    Joined:
    Nov 9, 2007
    Location:
    Colchester, UK
    #2
    It's gonna be hard to help without seeing some code.
     
  3. annguyen thread starter macrumors newbie

    Joined:
    Oct 2, 2008
    #3
    Luke Redpath, thanks for reading by issue.

    I can't post my whole punch of codes here. But here is the piece where the issue happens...

    Code:
    
    for (CellView *ball in spawningList) {
    	// checking some rules...
    (1)
    }
    (2)
    [spawningList removeAllObjects];
    (3)
    
    
    CellView is my custom UIImageView, spawningList is the NSMutableArray.
    At (1), I am pretty sure that I don't touch anything to release my objects.

    At (2) all objects in spawningList still have retainCount = 3 or 4

    At (3), after removing all objects from spawningList, 1 of those objects got released and its retainCount is now 0. This occurs intermittently.

    How could an object's retainCount decreased by 3 through 1 call of releasing! :(

    Does anyone have an idea what's wrong with it? Much appreciated that.
     
  4. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #4
    Is this an iPhone application? Because I was under the impression that Cocoa on the iPhone did not support garbage collection...
     
  5. annguyen thread starter macrumors newbie

    Joined:
    Oct 2, 2008
    #5
    yep. it's an iPhone app.
     
  6. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #6
    And you have Objective-C 2.0 Garbage Collection turned on? If so that's probably part of the problem.

    Or do you not actually mean Garbage Collection? If you are using GC you don't need to retain/release so this all looks wrong. Of course GC doesn't work in the iPhone so you can't use it on an actual device. I think you are confused with your terminology.
     
  7. annguyen thread starter macrumors newbie

    Joined:
    Oct 2, 2008
    #7
    Thanks for reading and reply.

    I don't think the GC work on iPhone. All retain/release stuffs work fine everywhere else. if the retain/release don't work then my code should not work from the very beginning, but the issue is not easy to reproduce. The piece of codes I posted is executed thousand times before causing the issue.
     
  8. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #8
    I know GC does not work in the iPhone: you are the one working on an iPhone application who claims and object is being released by GC. So let's get this straight: there is no GC involved. At some point in your code one or more object reach retain count zero and get deallocated and you can't work out why.

    The only way that anyone can help you is for you to post all of the relevant code. What you posted above is no help whatsoever. If this is a commercial product and you are unwilling to post the code, then you should accept that you will not get answers (and if you are being paid to do this it's unethical for you to expect your employers to pay you if you are not).
     
  9. annguyen thread starter macrumors newbie

    Joined:
    Oct 2, 2008
    #9
    Fair enough. ;)

    Please help me out, this is the code..

    Code:
    - (void) spawnedPieces {
    	if (state.spawningPieces > 0) {
    		state.spawningPieces--;
    	}
    	if (state.spawningPieces > 0) {
    		return;
    	}
    	
    	state.toGenerateNextPieces = YES;
    	state.newScore = 0;
    	for (CellView *ball in spawningList) {
    		// check five at new generated ball's position
    		CGPoint indexPoint = [ball indexPoint];
    		
    		if ([cells[(int)indexPoint.y][(int)indexPoint.x] value] == 0) {
    			[cells[(int)indexPoint.y][(int)indexPoint.x] release];
    			cells[(int)indexPoint.y][(int)indexPoint.x] = [ball retain];
    			[tiles[(int)indexPoint.y][(int)indexPoint.x] addSubview:cells[(int)indexPoint.y][(int)indexPoint.x]];
    			[cells[(int)indexPoint.y][(int)indexPoint.x] spawn];
    			balls[(int)indexPoint.y][(int)indexPoint.x] = [cells[(int)indexPoint.y][(int)indexPoint.x] value];
    		}
    		
    		int newScore = [self checkScoreFromPoint:indexPoint];
    		if (newScore > 0) {
    			CGPoint boundPoint = [GameHelper convertToBoundPointFromIndexPoint:indexPoint];
    			[self scored:newScore atPoint:boundPoint];
    		}
    	}
    	
    	[spawningList removeAllObjects];
    }
    
    
    - cells array contains all CellView objects which are my custom UIImageView.
    - tiles array is another array of parent view which will contains each cell in each tile.
    - the scored: atPoint: function is to popup the number of score on screen
    - checkScoreFromPoint: function is to check if player earn score at a specified point.
    - the spawningList won't contain more than 3 cells at once. It's allocated by other function, in this function I am posting, I just check the if new spawn cells make some scores then remove all objects in the spawningList.
     
  10. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #10
    What happens if [cells[(int)indexPoint.y][(int)indexPoint.x] value] != 0 more times than there are items in spawningList?

    I would assume objects in spawningList are retained by the NSArray and nothing else (i.e. were added to the NSArray autoreleased). So calling removeAll would cause all items in spawningList to get dealloced unless they had been added to the cells array (and retained)...
     
  11. annguyen thread starter macrumors newbie

    Joined:
    Oct 2, 2008
    #11
    The
    Code:
    if ([cells[(int)indexPoint.y][(int)indexPoint.x] value] == 0) {}
    block is to make sure the
    Code:
    ball
    object in spawningList is put in the cells array. I put it in for debugging purpose, but forgot to remove when posting here. Sorry.

    You are right.

    The objects in spawningList already is a sub-View of tiles array, its retainCount always greater than 2, and it reaches to 0 with one call of removeAllObjects by the NSArray.

    Appreciated for your time spending on my issue.
     
  12. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #12
    If the entire block that does all the release/retains etc is removed then I'm not sure how much more advice can be given without seeing whatever code sets up spawningList...
     
  13. annguyen thread starter macrumors newbie

    Joined:
    Oct 2, 2008
    #13
    Here it is...

    Code:
    - (void) nextPieces:(int)numberOfPieces newGame:(BOOL)isNewGame {
    	if (spawningList == nil) {
    		spawningList = [NSMutableSet setWithCapacity:0];
    		[spawningList retain];
    	}
    	
    	state.toGenerateNextPieces = NO;
    	state.state = GAME_STATE_SHOWING_NEXT_PIECE;
    	if (!isNewGame) {
    		for (int i = 0; i < numberOfPieces; i++) {
    			CGPoint point = [self randomIndexPoint];
    			
    			if ((int)point.x == COLS && (int)point.y == ROWS) {
    				// NSLog(@"no space");
    				noSpace = YES;
    				break;
    			}
    			
    			int index = [self randomValue:currentLevelFeature.numberOfPieces];
    			CellView *newCell;
    			newCell = [GameHelper createNextCellViewFromIndexPoint:point andPieceIndex:index];
    
    			[spawningList addObject:newCell];
    				
    			cells[(int)point.y][(int)point.x] = newCell;
    			balls[(int)point.y][(int)point.x] = [newCell value];
    				
    			[tiles[(int)point.y][(int)point.x] addSubview:newCell];
    		}
    	}
    }
    
    - The spawningList is reusable so it won't be released, I just init it once then release all objects it contains in the spawnedPieces method.
    - [GameHelper createNextCellViewFromIndexPoint:point andPieceIndex:index]; is to create a new CellView object
    - The randomIndexPoint method is to return the available indexPoint randomly
     
  14. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #14
    I assume the value returned from createNextCellViewFromIndexPoint: is autoreleased? Not that it should make much difference...

    Assume no other code ever does anything to release the CellView created I cannot see why this would get dealloced. There must be somewhere else in your code where you have made an error and either removed the view from the superview without retaining it first or similar...
     
  15. annguyen thread starter macrumors newbie

    Joined:
    Oct 2, 2008
    #15
    Hi robbieduncan,

    The value returned from createNextCellViewFromIndexPoint: is NOT autoreleased :(

    I have spent times to debug the whole app's process... but with no luck.

    Thanks for your help anyway. Much appreciated it.
     
  16. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #16
    Some comments on this problem:

    Your use of C style arrays is not a wise idea. Putting objects into C style arrays usually leads to memory leaks or crashes. I understand that you're also putting the objects into a MutableSet but all of your unnecessary typecasts and long lines of square brackets and parens makes the code very hard to read.

    One way that removeAllObjects could cause an object with retain count 3 to go to 0 would be if two objects in the array have retained each other. I don't see that in this code but that would be one way this could happen.

    How do you know the retain counts? I don't see code that checks that here.

    Things you can do to debug this include use of NSAssertion. Add assertions throughout this code to check all the conditions that you think should be required that may not be the case. The assertions are a little harsh in that they throw a run-time exception if they fail but this is a good way to check your assumptions.

    If you don't want to use the assertions just add some kind of debugging code that checks your conditions and then set a breakpoint that gets hit if the check fails. If it takes thousands of iterations to fail then you obviously can't step through it in the debugger. You need some kind of checks in the code at runtime to figure this out.

    Is it possible that you're running out of memory? Implement didReceiveMemoryWarning in your app delegate and log or hit a breakpoint if it's called. If you run out of memory it's possible that a memory allocation will fail that your code assumes always works, resulting in problems like you're seeing.

    You can override release in your objects for debugging and see how many times the objects are being released and who is releasing them.
     
  17. annguyen thread starter macrumors newbie

    Joined:
    Oct 2, 2008
    #17
    That was my first try with iPhone dev. Been busy at work and I just don't see any wrong from code so I still stuck there. That's why I haven't rewritten it.

    I am posting the issue here in hoping to know if someone has same problems, but things isn't what I expected. It's probably my only code. I will rewrite it someday.

    Thanks guys for helping.
     

Share This Page