Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In iOS, using ARC, is it sufficient to set all ivars and properties to nil, and release context, image, color space in viewDidUnload?

For iOS apps, using ARC, do we typically release these in viewDidUnload?

  1. set all instance variables to nil

  2. set all properties to nil

  3. Release any context using CGContextRelease, CGImage with CGImageRelease, and color space with CGColorSpaceRelease (releasing any non object)

  4. no special attention needed for NSMutableArray of NSSet elements: just set the reference to NSMutableArray and NSSet to nil, and each element will be automatically released.

Will doing these handle most memory release under ARC? Are there other items that need to be released as well?

like image 887
nonopolarity Avatar asked Jun 07 '12 17:06

nonopolarity


2 Answers

A lot of people misunderstand the point of viewDidUnload. In particular, it is not the counterpart to viewDidLoad. In most cases, your view controller will be deallocated without viewDidUnload being called. For this reason, you should never consider a deallocation in viewDidUnload a proper balance for an allocation in viewDidLoad.

viewDidUnload has been deprecated by Apple. Possibly the best argument against using it is its header (which I've wrapped):

- (void)viewDidUnload NS_DEPRECATED_IOS(3_0,6_0); // Called after the view
    // controller's view is released and set to nil. For example, a memory warning
    // which causes the view to be purged. Not invoked as a result of -dealloc.`

So what was viewDidUnload? The idea behind it is that the view is being unloaded out from behind your view controller. This gives you a chance to detach any pointers to it and clear any information you can rebuild easily. Your view will probably be loaded back in, at which point you'll need to rebuild any caches. Apple describes this:

When a low-memory condition occurs and the current view controller’s views are not needed, the system may opt to remove those views from memory. This method is called after the view controller’s view has been released and is your chance to perform any final cleanup. If your view controller stores separate references to the view or its subviews, you should use this method to release those references. You can also use this method to remove references to any objects that you created to support the view but that are no longer needed now that the view is gone. You should not use this method to release user data or any other information that cannot be easily recreated.

Keep in mind that zeroing out references to objects in viewDidUnload should be unnecessary now. If you're using ARC per Apple's recommendations, your view outlets are zeroing weak references. They'll automatically be nilled without you writing viewDidUnload!

Further, clearing out caching information fits better into didReceiveMemoryWarning, so you should probably write it instead:

You can override this method to release any additional memory used by your view controller. If you do, your implementation of this method must call the super implementation at some point to allow the view controller to release its view. If your view controller holds references to views in the view hierarchy, you should release those references in the viewDidUnload method instead.

Generally, the stuff people put in viewDidUnload is better handled in viewDidDisappear or dealloc. The only thing left for viewDidUnload is nilling any of your caches that can be rebuilt without data loss while the view controller is still open, when needed at some point after the view has been reloaded. (And, again, this should be handled in didReceiveMemoryWarning.) These caches should be built lazily; when your app needs them again, it will quietly rebuild them.

So what should you do in viewDidUnload? If you're using ARC: Nothing. Don't even write it. In fact, in the time since this answer was written Apple has deprecated viewDidUnload.

For CGContextRelease, the CGContext resource is not an Objective-C object. (You pointed this out, but I want to repeat it for posterity.) As such, it can not be automatically deallocated by ARC. You are responsible for making sure it's deallocated and nilled just as with the old Manual Retain Release (MRR) memory management scheme.

If you put this code in viewDidUnload, there is not guarantee it will ever be called. It must go in dealloc. You could put it in viewDidUnload as well, but…

And so:

  1. Not necessary or helpful. Your instance variables are minuscule compared to the view hierarchy.
  2. Not necessary or helpful. Your properties are minuscule compared to the view hierarchy (as long as your properties are not strong references into the view hierarchy).
  3. This will cause a memory leak, as dealloc will usually be called without viewDidUnload.
  4. Not necessary or helpful. See point 1 & 2.
like image 157
Steven Fisher Avatar answered Oct 26 '22 23:10

Steven Fisher


The viewDidUnload has a tricky name, it is very easy to know what goes in there if you think about it properly.

First thing you have to know is that the iOS devices have a low memory handling method. This means that when the device needs more memory it will check which of its apps it can free memory from. It does this by calling the ViewDidUnload method (which might be improperly named).

So you are encouraged to set EVERYTHING that can be reconstructed to nil here. (Everything that you created in the viewdidload).

The exceptions are when you really cant afford to lose an object because of the time it might take to get the data or something.

If you do not implement this viewdidload your app will hold onto its items and objects and the iOS wont be able to free anything from it.

SO basically like I said, release (by setting the elements pointing to those objects to nil) everything that you can safely reconstruct in the viewdidload. (which will be called for sure after the view has been unloaded and wants to be loaded again)

like image 21
Pochi Avatar answered Oct 27 '22 01:10

Pochi