Why is my Objective-C object freed?

I have a problem with an Objective-C object (in an iOS game application) that is mysteriously freed up.

The object is an instance of GameCharacter, which is created in this way:

for (int c = 0; c < kNrOfGuards; c++) { GameCharacter* guard = [[GameCharacter alloc] initGuard:self sprite:guardSprite]; [characterArray addObject:guard]; [guard release]; } 

I also have a convenient method for searching for GameCharacter:

 - (GameCharacter*)findCharacterWithIndex:(int)index { return [characterArray objectAtIndex:index]; } 

And the code generating the error looks like this:

 for (int c = 0; c < [self characterCount]; c++) { GameCharacter* tempCharacter = [self findCharacterWithIndex:c]; if (tempCharacter.playerId == playerIndex]) { ... } } 

Running this code for some time (never right away) generates an error in the console:

[GameCharacter playerId]: message sent to freed instance 0x4e47560

Using the NSZombieEnabled trick, I managed to find the object (s) that was causing the problem, but I still can not understand why this object is being freed. Finding my code for "release" / "dealloc" gives no hints.

I tried to remove the “release” (and even add “save”!) To the alloc / init loop (see above), it seems to extend the application’s runtime, but will not completely fix the problem.

Any hints would be much appreciated!

EDIT

Thanks to quixoto, Olie, Eiko, tc., I found out that this is my GameCharacter object that is being released, but I still don't understand why. Here is the trace log in reverse chronological order:

 #0 -[GameCharacter dealloc] #1 objc_setProperty #2 -[TiledGroundLayer setSelectedCharacter:] #3 -[TiledGroundLayer selectNextCharacterForPlayer:searchStep:] #4 -[GameScene selectNextCharacter:] #5 -[GameScene endTurn] #6 -[HUDLayer onClickDone:] 

What happens here is that the user clicks “Finish”, the selected character on the screen changes and, therefore, the selectedCharacter property on the TiledGroundLayer (step No. 2-4). Since the selectedCharacter belongs to the previous GameCharacter object, it seems to be freed. But why is it not saved properly with NSMutableArray ( [characterArray addObject:guard]; )?

+6
memory objective-c iphone
source share
4 answers

Based on your update:

 #0 -[GameCharacter dealloc] #1 objc_setProperty #2 -[TiledGroundLayer setSelectedCharacter:] 

I would suggest that you release your existing object reference in your setter, and then save a new copy. However, if the new object is the same object as the existing link, you can send a retain message to the already freed object.

 -(void) setSelectedCharacter: (GameCharacter*) newCharacter { [character release]; // Oops if character == newCharacter character = [newCharacter retain]; } 
+1
source share

There is not enough code to find out what the problem is, but from the error message, I would suggest that the playerId object is something that is not saved. That is, it seems that your tempCharacter is fine, but not the playerId field.

If you

 @property(nonatomic,retain) SomeObject *playerId; 

then remember that

 playerId = foo; 

will NOT hold an object for you. You should use an accessor:

 self.playerId = foo; 

EDIT in response to Tom question-edit:

I absolutely guarantee you that objects placed in NSMutableArray are stored by this array until (a) they are deleted or (b) the array is released. So you can stop looking there, the problem is elsewhere. :)

One thing you can try is to add the following code to an object that is released when you think it shouldn't:

 #pragma mark - #pragma mark Memory-use debugging #define DEBUG_RETAIN_RELEASE 0 #define DEBUG_ALLOC_DEALLOC 0 #if DEBUG_ALLOC_DEALLOC static int allocCounter = 0; +(id)alloc { id me = [super alloc]; NSLog(@"%@ ALLOC (%2d): %@", [me class], ++allocCounter, me); return me; } #endif #if DEBUG_RETAIN_RELEASE - (id)retain { id result = [super retain]; NSLog(@"%@ retain %@, count: %2d", [self class], self, [self retainCount]); return result; } - (void)release { // we have to log BEFORE the release, in case it the last one! e NSLog(@"%@ RELEASE %@, count: %2d", [self class], self, ([self retainCount] - 1)); [super release]; } - (id)autorelease { id result = [super autorelease]; NSLog(@"%@ AUTOrelease %@, count: %2d", [self class], self, [self retainCount]); return result; } #endif // ... - (void)dealloc { #if DEBUG_ALLOC_DEALLOC NSLog(@"%@ dealloc (%2d): %@", [self class], --allocCounter, self); #endif [self releaseMyStuff]; [super dealloc]; } 

Then start with DEBUG_ALLOC_DEALLOC = 1 and set a breakpoint in the dealloc log statement. If this does not help, set DEBUG_RETAIN_RELEASE = 1 and unlock both save and release.

You will be surprised that all iOS you have, but don’t worry about it, iOS promises balanced release-release if used correctly. I am simply warning you, because you may expect much less deductions and you will be surprised to see that it rises during some kind of operation.

Luck!

+2
source share

Debugging false holds / releases in 3 easy steps:

  • Override -retain , -release and -autorelease for the class you are interested in. Record the message ( NSLog(@"%@ %s", self, sel_getName(_cmd)) ) and super -call.
  • Drag all these methods (onto super -call, that is, after the log message so that you know which particular object). Edit breakpoint; add the "bt" command and check the auto-continue box (or just use the two "bt", "continue" commands).
  • Clear log. Launch the app. Print a magazine. Attach it to the board. Draw a few arrows until you find a false release / autorelease .

My first impression was that characterArray was released too soon, but this should lead to him complaining about sending a message to the freed NSArray. Unless, of course, you are accessing characterArray from multiple threads (do not do this!).

+1
source share

You release a GameCharacter instance somewhere. Your code looks fine, so it’s somewhere in other places that use these objects.

0
source share

All Articles