1

Given that we are writing code with ARC, should I nil properties in viewDidUnload, that are instantiated from:

  1. XIB (here the nilling is sometimes generated from IDE)

  2. from initialiser and have not IBOutlet

  3. that are weak

?

Mazyod
  • 22,319
  • 10
  • 92
  • 157
Earl Grey
  • 7,426
  • 6
  • 39
  • 59

2 Answers2

1

Your general rules:

  1. nil all strong IBOutlets only. Leave weak ones alone.
  2. nil all properties instantiated in viewDidLoad, and not init, initWithCoder: and initWithNibName:bundle:.

You should also nil properties that are recreated "on-the-fly" or have a nil check, to free up more memory.

Mazyod
  • 22,319
  • 10
  • 92
  • 157
1

The purpose of viewDidUnload is to give your app a chance to remove references to user interface objects that may no longer exist because the view was removed upon receiving a memory warning. Thus:

  1. You should be setting any user interface controls to nil (because the view is being unloaded). Unnecessary for weak properties (and they generally should be weak per Apple guidance on this topic), but if Xcode inserts it in for you, it's not a problem. For guidance on what to do in viewDidUnload see the "Memory Warnings" section of the Resource Programming Guide: The Nib Files.

  2. And for non-user interface objects that you set up in viewDidLoad, I'd be wary about just blindly setting those to nil in viewDidUnload, especially if you're not using ARC (e.g. if you accidentally nil the instance variable, you might cause a leak). And you probably want to balance the amount of memory that will be recovered versus the "cost" of re-retrieving that data (e.g. if it's from some remote server). Regardless, I'd suggest that you handle the freeing of memory for non-UI objects in didReceiveMemoryWarning.

In my mind, I view viewDidUnload as a chance to make sure I'm not maintaining references to user interface objects that might no longer exist, and I use didReceiveMemoryWarning to empty caches or other non-UI related items that I can safely purge to recover some memory. And if you're concerned about iOS 6, note that the handling of viewDidUnload may be changing, and while the NDA precludes us from discussing it publicly, I might advise that you may want to refer to the iOS 6 Beta 4 Release Notes and look for references to viewDidUnload.

Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • Setting `weak` variables to `nil` is advisable? The idea behind `weak` references is that they are `nil`'d automatically for you. You should **never** need to nil a `weak` reference manually. And since `viewDidLoad` is always called after `viewDidUnload` if the view was needed again, `nil`ing non-UI properties created there is a good way to free up more memory. Finally, he is talking about properties. If you use `self.property = nil;` you will never leak (unless you are doing something terribly wrong). – Mazyod Sep 12 '12 at 09:24
  • @Mazyod Re weak to nil, you're quite right. Given that Xcode automatically adds the line of code that sets those weak `IBOutlet` properties to `nil` in `viewDidUnload` when you create the `IBOutlet` via Interface Builder, I was assuming that this would be considered good practice, but you're quite right that it is unnecessary for weak `IBOutlet` properties. It does no harm (e.g. no point in going through and deleting the lines of code that Xcode added), but is unnecessary. I have modified my answer accordingly. – Rob Sep 12 '12 at 13:34
  • @Mazyod Regarding your comment about if you set the property to `nil`, you won't leak: I agree, but my comment was about those cases where someone accidentally sets the _property's instance variable_ to `nil`. (And new programmers invariable screw up property references with those property's instance variables.) The bigger point, though, that just because it's a property, you shouldn't blithely be `nil`-ing them. It's just the UI properties. Non UI properties (a) should be handled case by case; and (b) probably shouldn't be done in `viewDidUnload` regardless. – Rob Sep 12 '12 at 13:43
  • OK, your answer no longer deserves a down-vote. We are always learning :) .. However, please note that Xcode does **not** add the `self.outlet = nil;` automatically for `weak` outlets, becuase it's not needed. Only `strong` outlets need to be `nil`'d. Read more about it here: http://stackoverflow.com/questions/11341818/setting-weak-to-a-non-property-variable – Mazyod Sep 12 '12 at 13:45
  • 1
    @Mazyod Not to belabor the point, but if you create an `IBOutlet` in an ARC project in Xcode 4.4 (and this was true in earlier versions, too) by control dragging from the control in Interface Builder to the .h in the assistance editor, Xcode gives you a popup to create the `IBOutlet` automatically for you, and when you do it this way, it inserts a `[self setYourProperty:nil];` in `viewDidUnload` as well. I know it's unnecessary, but that's what Xcode does. – Rob Sep 12 '12 at 13:51
  • Sure, actually thanks for pointing that out. I am still supporting iOS 4 in my apps, so I didn't really see it for my self.. And you are right... Very weird. I'll go search about it. – Mazyod Sep 12 '12 at 13:57