Leaking object by calling addChild - objective-c

I have a custom class called Hexagon which is a subclass from NSObject. However when I assign it to a sprite and add it to the screen by calling -addChild:, it has a retain count of 2! What should I do, in order to stop that leakage ?
for (int i =0; i < HEXCOUNT; i++){
Hexagon *nHex = [[Hexagon alloc]initWithDicitonary:hexPositions];
CCSprite *theSprite = (CCSprite*)nHex;
NSString *hexName = [NSString stringWithFormat:#"hexagon%d", i];
CGPoint location = CGPointFromString([[EXHEXAGONS objectForKey:hexName]objectForKey:#"position"]);
CGPoint nLocation = ccp(screenSize.width/2 + 68 * location.x,screenSize.height/2 + 39 * location.y);
theSprite.position = nLocation;
[self addChild:theSprite z:1 tag:i];
NSMutableDictionary *hexProperties = [EXHEXAGONS objectForKey:hexName];
[hexProperties setObject:theSprite forKey:#"realSprite"];
[EXHEXAGONS setObject:hexProperties forKey:hexName] ;
[[GameStateSingleton sharedMySingleton]setExistingHexagons:EXHEXAGONS];
[nHex release];
}

Don't rely on retainCount for anything. A retainCount of 2 doesn't mean the object is leaking. Only Instruments can tell you that.
Creating the Hexagon object with alloc/init will add a retain count of +1. Adding it as child will add +1. So depending on where you log the retainCount, it may be correct.
If you worry about memory leaks, by all means start using ARC.

First off, worrying about retain counts is not productive unless you are verifying that it is not getting deallocated when fully released from all the various objects which retain it.
Secondly, presumably you are putting the object into a NSArray, NSSet, or NSDictionary within addChild:z:tag:? So, that would bump it's retain count up by one.
You also cast your Hexagon object to a CCSprite and add it to the NSDictionary hexProperties, which will add another 1 to your retain count.
By the time you release your object at the bottom of the loop, your retain count will be at least 3. After the release it should be at least 2.

Related

Why does my NSArray get deallocated?

I'm trying to understand Automatic Reference Counting, as I come from a high-level programming language (Python) and I'm working on a project which use this feature of Objective-C. I often get problems with ARC deallocating objects which I need later, but now I got a concrete example for which I hope I'll get an explanation.
- (void) animateGun:(UIImageView *)gun withFilmStrip:(UIImage *)filmstrip{
NSMutableArray *frames = [[NSMutableArray alloc] init];
NSInteger framesno = filmstrip.size.width / gun_width;
for (int x=0; x<framesno; x++){
CGImageRef cFrame = CGImageCreateWithImageInRect(filmstrip.CGImage, CGRectMake(x * gun_width, 0, gun_width, gun_height));
[frames addObject:[UIImage imageWithCGImage:cFrame]];
CGImageRelease(cFrame);
}
gun.image = [frames objectAtIndex:0];
gun.animationImages = frames;
gun.animationDuration = .8;
gun.animationRepeatCount = 1;
[gun startAnimating];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(arc4random() % 300)/100 * NSEC_PER_SEC), dispatch_get_current_queue(),^{
[self animateGun:leftGun withFilmStrip:[self getFilmStripForAction:gunShoot andTeam:nil withWeapon:nil]];
});
}
The idea behind this snippet of code is simple: I have a (UIImageView*)gun which I animate with the images stored in (NSMutableArray *)frames, at random times. (UIImage *)filmstrip is just an image which contains all the frames which will be used on animation. The first iteration of animation works, but the problems appears on the second iteration, where I get -[UIImage _isResizable]: message sent to deallocated instance ... or -[UIImage _contentStretchInPixels]: message sent to deallocated instance ... or -[NSArrayI release]: message sent to deallocated instance .... This happens at
gun.animationImages = frames;
but I don't understand why. I'm not requesting a fix for my issue, but just to help me understand what's happening here. Thanks.
ARC is a mechanism that removes the need to manually retain/release objects. Here's a nice site that explains how this works: http://longweekendmobile.com/2011/09/07/objc-automatic-reference-counting-in-xcode-explained/
Try changing "leftGun" for "gun". I think that's probably the one that gets deallocated at some point, if you're using it through an ivar. Otherwise, leftGun simply isn't in the scope.
Here's what it should look like:
In your .h file:
#property (nonatomic, strong) IBOutlet UIImageView *leftGun;
In your .m file:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(arc4random() % 300)/100 * NSEC_PER_SEC), dispatch_get_current_queue(),^{
[self animateGun:gun withFilmStrip:[self getFilmStripForAction:gunShoot andTeam:nil withWeapon:nil]];
});
Also, not quite sure where "gunShoot" is coming from. Is that supposed to be an enum?
EDIT
Added an example of how the leftGun property should be defined. The reason behind using a property over an ivar is for memory management purposes. If you want to release or destroy an object that is a property, simply set it to nil and the property will take care of releasing the object if it has to.
You may prevent the deallocation of the frames array if you mark it as __block.
__block NSMutableArray *frames = [NSMutableArray array];
see “The __block Storage Type.”

Why does the reference count when retrieving object from container not increase?

I have created a little test project to try to resolve a problem I am having in my main project. I've noticed that when retrieving an object from a container the reference count dosen't increment.
I am confused why this is not the case?
For example this code will not increase the reference count of the hereDoggy object:
//Retrieve the dog, why does this not increment the reference count?
Dog* hereDoggy = [cont1 objectAtIndex:0];
Below is the full example:
-(void)doZombieProblem
{
NSMutableArray* cont1 = [NSMutableArray array];
NSMutableArray* cont2 = [NSMutableArray array];
NSMutableArray* cont3 = nil;
//Create the dog pointer
Dog* doggy = [[Dog alloc] initWithName:#"Bernard"];
//Add to container1
[cont1 addObject:doggy];
//Release the dog pointer
[doggy release];
while ([cont1 count] > 0)
{
//Retrieve the dog, why does this not increment the reference count?
Dog* hereDoggy = [cont1 objectAtIndex:0];
//Add it to cont2
[cont2 addObject:hereDoggy];
//Remove it from cont1.
[cont1 removeObjectAtIndex:0];
//No need to release as we haven't increased the reference count.
//[hereDoggy release];
}
//I should be able to retrieve the dog here from cont2.
Dog* bernard = [cont2 objectAtIndex:0];
//No need to release as we haven't increased the reference count.
//[bernard release];
}
In this case, if you want to increase the retain count for your object you need to send a retain (or a copy) message.
As a rule of thumb
You need always to balance your retains (or copyies) with your releases. If you don't do it you can have memory leaks. Otherwise switch to the ARC feature to avoid the code amount to write and simplify your life.
Here a useful link to understand how Memory Management works.
MemoryMgmt
I commented your code to understand what is going on:
// the object referenced by doggy has a retain count of 1
Dog* doggy = [[Dog alloc] initWithName:#"Bernard"];
// now the retain count is 2 since you added to a container class like NSArray
[cont1 addObject:doggy];
// now the retain count is 1
[doggy release];
Then, within the while statement:
// the retain count still remains 1
Dog* hereDoggy = [cont1 objectAtIndex:0];
// the retain count increases to 2
[cont2 addObject:hereDoggy];
// the retain count goes to 1
[cont1 removeObjectAtIndex:0];
Since, the object is maintained alive by cont2 you are able to access it.
If you do [cont2 removeObjectAtIndex:0]; the retain count reaches 0 and the object is deallocated automatically.
It's your responsibility as the user of the object to manage it's retain count. This is because only you, the consumer, know when you are done with it. That's why just calling [cont1 objectAtIndex:0] doesn't increment it. NSArray has no clue what you have planned with the object it returns.
Think of retain count to indicate the number of things owning something. When it's 0, no one owns it, so let it be garbage collected. If it's 1, then only 1 thing needs it/owns it (and on up).
When you call [cont1 addObject:doggy] NSMutableArray will absolutely increment the retain count on it (behind the scenes), just like when you call [cont1 removeObjectAtIndex:0] NSMutableArray will decrement the retain count on it.
Now, if you need hereDoggy for any period of time, just call retain on it yourself, and then release where appropriate.

Memory Leak - Objective c [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Objective C Memory Management
My code is showing a memory leak here:
NSMutableArray* newImageArray = [[NSMutableArray alloc] init];
NSMutableArray* newMediaArray = [[NSMutableArray alloc] init];
if (self.categoryIndex == 0) {
for (int i=1; i < [categoryArray count]; i++)
{
newImageArray = [NSMutableArray arrayWithArray:[newImageArray arrayByAddingObjectsFromArray:[self getImageArrayByCategoryIndex:i]]];
}
}
else {
newImageArray = [self getImageArrayByCategoryIndex:self.categoryIndex];
}
for (int i=0; i < [newImageArray count]; i++)
{
Media* media = [[Media alloc] init];
NSString* imageFile = [newImageArray objectAtIndex: i];
media.imageFile = [UIImage imageNamed:imageFile];
media.imageLabel = [[imageFile lastPathComponent] stringByDeletingPathExtension];
media.soundFile = [appFolderPath stringByAppendingString:[[[imageFile stringByDeletingPathExtension] stringByAppendingString: #".wav"] stringByReplacingOccurrencesOfString: IMAGES_FOLDER withString: SOUNDS_FOLDER]];
[newMediaArray addObject:media];
}
self.mediaArray = newMediaArray;
[self setNextMediaIndex];
I am not releasing media because it is being used by newMediaArray (which is used by mediaArray, which is used my my main object). Shouldn't everything get released when I release my main object?
It looks like you are leaking all over the place in a variety of ways
newImageArray gets allocated but never released, additionaly you are overwriting the version that you allocated in the first line of you code with another version. So even if you released it at the end of this code segment, the wrong version would get released. It looks like you don't even need to allocate this one.
newMediaArray gets allocated but never released, you assign it to a property mediaArray if you are using #synthesize to create the code for that property, depending on how you declared that property, the setter will retain the value i.e. newMediaArray creating a leak.
media gets allocated but never released, it get added to a NSMutableArray which means it will get retained by the array. If your app crashes when you release media in the for loop the problem is somewhere else
The Memory Management Programming Guide is pretty much a must read
When an NSMutableArray such as newMediaArray adds an object, it will retain that object. You don't need to (nor should you) retain the object on the array's behalf. This is fundamentally how memory management in Objective-C works: each object retains the things it references, and releases them when finished. newMediaArray is its own object, so it'll manage its own references.
You should release media near the end of the body of your for loop because you're done using that object. If you don't release it then, you'll lose your reference to it and you'll have no way to release it in the future.
You do
[newMediaArray addObject:media];
that means that newMediaArray has done a retain on media. You can then release media (you should). The retain done in the array method will keep it alive as long as the array references it. If you don't release it in your method, the retain count will remain 2, and even if the array releases it, it will still be 1 and not be dealloc-ed.
You could do:
Media *media = [[[Media alloc] init] autorelease];
Then the autorelease pool will release it in time, but not before this method ends.
You need to have the [media release] statement at the bottom of the loop. newMediaArray should also be released after it is assigned to the mediArray property.

Objective-C ref count and autorelease

Hey guys, suppose the following code:
int main (int argc, const char * argv[])
{
//[...]
Rectangle* myRect = [[Rectangle alloc] init];
Vector2* newOrigin = [[[Vector2 alloc] init] autorelease]; // ref count 1
[newOrigin setX: 50.0f];
[myRect setOrigin: newOrigin]; // ref count 2
[myRect.origin setXY: 25.0f :100.0f]; // ref count goes to 3... why ?
[myRect release];
[pool drain];
return 0;
}
Rectangle's origin is declared as a (retain) synthesized property.
Just wondering 2 things:
Why does ref count goes to 3 when using the getter accessor of Rectangle's origin? Am I doing something wrong ?
With a ref count of 3, I don't understand how this snippet of code cannot leak. Calling release on myRect will make it go down to 2 since I call release on the origin in dealloc(). But then, when does autorelease take effect?
Thanks!
Why does ref count goes to 3 when
using the getter accessor of
Rectangle's origin?
Because your #property is declared as atomic (the default) and, thus, the synthesized getter retains and then autoreleases the return value.
Am I doing something wrong ?
Yes. You are studying absolute retain counts.
The absolute retain counts of any object is quite thoroughly useless to consider. You only care about deltas; if you cause the retain count to increase, you must cause it to decrease.
With a ref count of 3, I don't
understand how this snippet of code
cannot leak. Calling release on myRect
will make it go down to 2 since I call
release on the origin in dealloc().
But then, when does autorelease take
effect?
An autorelease is simply a delayed release that kicks in when the containing pool is drained. So, in your case, the object will be deallocated when [pool drain]; is executed.
From Apple's documentation on -retainCount:
Important: This method is typically of
no value in debugging memory
management issues. Because any number
of framework objects may have retained
an object in order to hold references
to it, while at the same time
autorelease pools may be holding any
number of deferred releases on an
object, it is very unlikely that you
can get useful information from this
method.

Objective C Array and Object Release

I have a newbie question regarding when to release the elements of a NSArray. See following pseudo code:
NSMutalbeArray *2DArray = [[NSMutableArray alloc] initWithCapacity:10];
for (int i=0;i<10;i++) {
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:5];
for (int j=0;j<5;j++) {
MyObject *obj = [[MyObject alloc] init];
[array addObject:obj];
[obj release];
}
[2DArray addObject:array];
[array release];
}
// use 2DArray to do something
[2DArray release]
My question here is, when I release 2DArray, do I need to explicitly release each of its element (array) first? Also, before I release the "array" object, do I need to release each of its element (MyObject) first?
I am new to Objective C. Please help. thanks.
No, you don't need to tell each object to be released. When you send a release method to an NSArray, it automatically sends a release method to each item inside first.
So in your case, you send [2DArray release]. This automatically sends [array release] to every other array, which sends [obj release] to each object inside each array.
You don't need to release the kept objects. NSArray retains them when you add, and releases them when released. So if you allocate, add to the array, then release, the object in the array will have the retain count of 1. Once the array is freed, the object is released, therefore freed.
When an object is created, it has a retain count of 1. Whenever a object is added to an array, its retain count is increased (in this case to 2). After adding to the array, your code release its hold of the object, dropping its retain count by 1 (to 1 in this case). Then when you release the array, it calls release on everything in it dropping their retain counts by 1 (to 0 in this case). When retain count hits 0 the object is deallocated.
Your code looks correct from a memory management stand point.