BIT-101 [2003-2017]

Objective-C Memory Management tip o' the day


Still getting used to this whole memory management thing. I thought I had it pretty much squared away, but just ran into a spot where I got complacent and let a bunch get by me.

I’ve been working mostly with cocos2d, where most of the objects are created with a static “node” or “spriteWith…” type methods, which return an autoreleased instance of the class you want.

[c]mySprite = [Sprite spriteWithFile:@“some.png”];
myScene = [SomeScene node];[/c]

Since these autoreleased, you need to immediately do something that’s going to retain them if you want to keep them around. In most cases, with something like a sprite, you are adding the sprite as a child of another object, which retains the sprite that is added. In some cases, you might be adding it to an array, which also retains it. In these cases, that’s usually all you want to do, because then when you remove it from the parent or the array, or release the array or whatever, the instance is released and dealloc’ed.

[c]mySprite = [Sprite spriteWithFile:@“some.png”]; // autorelease
[myScene addChild:mySprite]; // retains mySprite
… later …
[myScene removeChild:mySprite]; // releases mySprite. retainCount reaches 0, and it’s dealloced[/c]

Of course, if you want the sprite to stick around after removing it from the parent, retain it explicitly. Also, if you are NOT immediately adding the autoreleased object to something that will retain it, you will need to explicitly retain it:

[c]mySprite = [[Sprite spriteWithFile:@“some.png”] retain];[/c]

Now it will stick around, so you can add it to a parent object later. But remember, when you remove it from the parent, it will still have a retainCount of 1, so when you are really done with it, you’ll need to give it one more release:

[c][mySprite release];[/c]

So this brings me to where I messed up. Again, I got really used to these autoreleased objects. But then I created several “regular” objects for my model, using alloc/init, and added these to an array. I was stuck in autorelease mode, so I was doing something like this:

[c]myModelObject = [[ModelObject alloc] init];
[modelArray addObject:myModelObject];[/c]

Of course, when you alloc something, it gets a retain count of 1. This is not autoreleased. Adding it to the array, retains it again. Later, I was removing the object from the array, thinking that was the end of that. But it still had a retain count of 1. I wound up with a bunch of model objects never getting dealloced. Worse, these model objects were holding a reference to the view (I know, I know, questionable architecture to say the least), so even after the view (which was a cocos2d sprite) was removed from its parent, it was still being retained by the model and was sticking around, eating up not only memory, but running animations behind the scenes. The solution was simple:

[c]myModelObject = [[ModelObject alloc] init];
[modelArray addObject:myModelObject];
[myModelObject release][/c]

You’re safe to release it here, because the array is retaining it.

Now, this wasn’t some blinding realization. As soon as I saw the alloc/init without a release, it was a “duh!” moment. Found these in several places, cleaned them up and got a stellar performance boost. (Now I’m going to clean up that model/view connection.)

Anyway, not really sure what the point of this is. Just one of those things where you’re happy to find something big that really helps your app and you want to share it with someone. My wife and daughter didn’t really care. 🙂

« Previous Post
Next Post »