This is basically related to my other question here
I’m trying to release the NSMutableArray which contains viewControllers. I do:
self.viewControllers = nil;
In viewWillDisappear because I’m moving to another view. But no matter what I do the view Controllers are not released. I also tried:
[[scrollView subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
Where scrollview is the view owning the containing NSMutableArray.
I see the count of live view controllers (in instruments) not changing although the reference count of the containing NSMutableArray is 0.
A couple of observations:
Make sure you run your non-ARC code through the static analyzer. This can find many memory management issues that plague non-ARC code. Select “Analyze” from the “Product” menu in Xcode, or press command+shift+B. A lot of these memory management issues go away if you use ARC, but if you’re not using ARC, the static analyzer can be invaluable in examining your code.
Your attempt to
removeFromSuperviewis unnecessary, and would not affect theretainCountof the view controllers, themselves. Do I infer from this attempt, though, that you’ve created view controllers and then added their views to the scroll view? If so, did you do the necessaryaddChildViewControllerfor each of those? If so, you do need to do the associatedremoveFromParentViewControllerfor each of those, though.The proper deallocation of the view controllers is a function of how you defined and allocated the
viewControllersarray, and how you populated it.But, for example, I have a property:
And I initialized it with the following code (note the
autoreleaseof theNSMutableArrayitself (since I’m using the accessor method which will retain it for me), and the explicitreleaseof theObjectobjects):If I examine the
retainCountvalues, I can see that everything has aretainCountof +1, as is appropriate:It (and the array’s individual objects) are properly deallocated when I clear it in the following method (a fact verified by the fact that the
Objectclass does aNSLogduring itsdeallocmethod):This is all a long-winded way of saying that your syntax of
self.viewControllers = nil;is a perfectly suitable way to release the array (and thus its member objects), assuming the array is defined as aretainproperty as illustrated in the previous point. But, if the array’s member objects are not getting released, then those objects are obviously not getting theirretainCountdown to zero. I would try, right before yourself.viewControllers = nil;, logging not only theretainCountof the array itself, but also theretainCountof the individual objects of your array, to confirm theirretainCountsettings.They should all have a
retainCountof +1 at that point (otherwise there is something else retaining them, either because they’ve been over-retained, you have some retain cycle (a.k.a. strong reference cycle) in those view controllers, or something else is legitimately retaining them (e.g. at some point you pushed one of those view controllers onto the navigator stack, but you haven’t yet popped them off)).If you’re still leaking, I would then use Instruments to find the leak. By the way, when examine the call tree for leaks, I find it useful to “Invert Call Tree” and to “Hide System Libraries”.
Update:
Above, in point 4, I warn of the risk of retain cycles. An example of a retain cycle is the use of a
NSTimerby the view controller and a failure toinvalidateandreleasethe timer when it’s time to release the view controller. Chatting with you offline, this sounds like this may be the issue, where you were trying toreleasetheNSTimerindealloc, but thedeallocwill never called because the timer, itself, is retaining the view controller. You need to manuallyinvalidateandreleasetheNSTimer(there by releasing the strong reference to the view controller) for any view controllers that have timers before you release theNSMutableArray. (E.g. maybe have a protocol for stopping timers, make your child view controllers conform to that.)