When running Analyzer, I receive the “Object sent -autorelease too many times” warning. I know I’m doing something tricky (and am open to alternatives to accomplishing my goal).
Essentially, I wanted to keep a stack of specific types of controllers handy for sending messages from a central location. So, considering:
From ‘ActionBroker’ shared object:
NSMutableSet *liveActions;
liveActions = [NSMutableSet alloc] init];
…
CLViewController *action = [[[actionClass alloc] init] autorelease];
if (!action) {
return nil;
}
[self.liveActions addObject: action];
// When adding an object, the retain count is increased. We want the action
// to dealloc, so that it might remove itself from the list...
[action release];
return action;
And the complementary dealloc code:
[[CLActionBroker sharedActionBroker] removeAction: self];
[super dealloc];
… and in removeAction:
[action retain];
[self.liveActions removeObject:action];
The above code works, I just get the nagging error. And the nagging sensation that I could probably solve the problem a different way.
One of the use cases for this code is to pass an ‘handleOpenURL’ request through a chain of open controllers and returning the first ‘YES’ response.
As I understand it, your intent is to have a set of controllers (“actions”) in the set, which you could easily access from anywhere in your app. If one of these controllers is deallocated, it would automatically remove itself from the set.
There’s a problem with this setup, though. As you’ve described it above, the controller is supposed to be removed from the
liveActionsset upon deallocation. But since an NSSet retains its members, your controller will never be deallocated so long as it is still in theliveActionsset.-deallocis only run when all retains have been balanced by a release.This, then leads to your over-release, which leads to the warning. Since you’ve sent an extra release,
-dealloccould be run while the controller is still in theliveActionsset. But when you remove it from that set, it’s going to send areleasemessage to your object, which would take its retain count negative. That may or may not be safe, but in either case it’s an ugly workaround.What you really want, it seems, is a set that does not retain its members. This is normally a dangerous configuration, since it can lead to dangling pointers in the set. But if you’re willing to manage the lifetime of the object and clear out those dangling pointers at the appropriate times, it turns out that it’s quite doable. You just need to use a
CFMutableSetinstead of anNSMutableSet. And since the two are toll-free bridged, it doesn’t even add that much complexity.Setting up the
CFMutableSetlooks like this:After that, you can use it exactly as you would use any other
NSMutableSet; this one will just be special in that it won’t retain its members.