views:

1855

answers:

5

I have a UIViewController which has a retainCount of 3 the moment I instantiate it. That stirs me as terribly incorrect. What's the best way of figuring out who bumped up the retainCount to 3? I'd imagine instantiating the object should give the pointer 1, then I suppose maybe pushing it onto the UINavigationController's stack might bump it up one (not sure about that though?), but the third.. is a mystery.

+15  A: 

Don't ever rely on retain counts directly. What's happened is that during the initialization process, some piece of code has retained and autoreleased the object. Because you can't tell how many times an object has been autoreleased, you don't actually know what the real retain count is.

Retain counts should only be used as a debugging aid, never as program control flow.

As long as you follow all of the rules laid out in the Memory Management Programming Guide for Cocoa, you won't have problems.

Adam Rosenfield
+1  A: 

What's the best way of figuring out who bumped up the retainCount to 3?

That's approaching the problem from the wrong angle. This will confuse you and will lead you astray (and probably right past) the actual problem, when indeed there is one.

Better to think about who owns the object. Do you intend to keep the object around as the value of one of your own properties? If so, then you are one of its owners. If not, then you aren't. If you pass the object to another object to store in one of its properties, then that other object is also an owner.

These ownerships are just relationships, so it's really easy to keep them straight in your head.

  • “This is one of my controllers. It owns the root objects of my model and one or more view[ controller]s.”
  • “This is a view. It owns some parts of my model.”
  • “This is part of my model. It owns primitive objects only.”
  • “This is another part of my model. It owns some primitive objects and some other bits of model.”

If you have a solid grasp of your ownerships, then you cannot write a memory leak except by forgetting a release or autorelease message (which can happen to anyone), and you will almost certainly not write a cyclic retention (two objects retaining each other) except knowingly and with copious comments and #warnings.

If you haven't worked out your ownerships, then you have probably written one or more memory leaks or cyclic retentions that you don't know about.

Peter Hosey
+11  A: 

Adam is right that you shouldn't be overly concerned about retain counts.

But if you ever have a legitimate need for solving such a mystery, a good technique is to subclass the affected class just so you can add overrides to the memory-management methods.

E.g. in a subclass of UIViewController, you could implement:

- (id) retain
{
    // Break here to see who is retaining me.
    return [super retain];
}
danielpunkass
How could you see who's retaining the object? The only argument is self, isn't it?
quano
quano - you look at the stack trace from the debugger. You'll see exactly who is calling retain.
danielpunkass
Great idea. Thanks!
mtc06
+1  A: 

It's not a 100% solution, but the LLVM Clang Static Analyzer can be a big help in tracking down incorrect manual memory management usage. Between the Static Analyzer and MallocDebug, you can get to be a pro at tracking down memory management issues very quickly. BTW, even though Instruments is the new hotness, I find MallocDebug far more reliable.

You can find the LLVM Clang Static Analyzer here: LLVM/Clang Static Analyzer

Jay O'Conor