64

Maybe this is a bad practice, but from the documentations that I read I got the advice to initialize objects in some cases inside the viewDidLoad method and nil it in viewDidUnload.

For example if you have something like adding an Observer

[[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(filterready:)
                                                 name:@"filterReady"
                                               object:nil];

Now I don't have a method to remove the Observer, however the viewDidLoad becomes called every time the view is shown which results in having multiple observers running after a while and the selector is then called multiple times.

I can fix this by moving some cleaners into the viewDidDisappear method, but now I have some doubts if I'm doing the right thing.

In my sample I have multiple Navigation Controllers that are controlling their subnavigations, but the dealloc is never called for them, even though they are not referenced

Hons
  • 3,804
  • 3
  • 32
  • 50

4 Answers4

110

You should use the - (void)didReceiveMemoryWarning and - (void)dealloc methods.

In iOS 6, the viewWillUnload and viewDidUnload methods of UIViewController are now deprecated. If you were using these methods to release data, use the didReceiveMemoryWarning method instead. You can also use this method to release references to the view controller’s view if it is not being used. You would need to test that the view is not in a window before doing this.

So you should check if your view is in the window first, then remove your observer in the didReceiveMemoryWarning

Alexander Farber
  • 21,519
  • 75
  • 241
  • 416
Alex Rouse
  • 1,681
  • 1
  • 12
  • 14
  • It's probably the right answer. Still it's strange, that they removed this message. I learned using the SDK by following Paul Hegarty's slides, and of course they are still for iOS5. I'm going to check for his updated slides this Year, maybe he's giving a good hint on this. – Hons Oct 08 '12 at 12:08
  • 2
    @Hons it's not strange at all — `viewDidUnload` was, explicitly per the documentation, called only if your view is unloaded on account of a memory warning. If you add an observer within `viewDidLoad` and remove it only in `viewDidUnload` then a lot of the time you're going to be deallocated without removing it. That'll leave a dangling pointer in the notification centre leading almost certainly to a crash later on. – Tommy Oct 31 '12 at 00:12
  • How do you check if your view is in the window? – zakdances Nov 14 '12 at 12:00
  • 4
    @yourfriendzak you can check if `view.window` is nil. – Groxx Nov 22 '12 at 00:47
  • 12
    @Groxx But beware - accessing 'view' will cause the view to be loaded if it isn't already. Even Apple gets this wrong in its sample code. You should use `if ([self isViewLoaded] && self.view.window)` – Mike Weller Apr 15 '13 at 15:46
  • 1
    Hah, good point. Thanks @MikeWeller, you're right! I think I discovered this and added the same check, but I never came back and updated things here. – Groxx Apr 15 '13 at 18:20
16

First of all, even when viewDidUnload was not deprecated, you must have had to unregister that notification in viewDidUnload AND dealloc. Even before iOS 6, viewDidUnload is NOT called in most circumstances; only in low memory situations. So if you had only put it in viewDidUnload and not dealloc before, it would not have been unregistered, and it would probably have crashed when it was deallocated and received a notification. So you must have had to put it in dealloc before, for it to have worked correctly.

Second, if you did it correctly before, you don't need to do anything extra for it to work correctly in iOS 6. The only difference in iOS 6 is that views are no longer unloaded at all (even in low memory situations). So it's the same as in iOS 5 when you didn't run into a low memory situation. Since views are not unloaded, viewDidLoad will only be called once, so your notification will only be registered once. It will be unregistered in dealloc, as you must have put it for it to have worked correctly.

user102008
  • 30,736
  • 10
  • 83
  • 104
10

Alex answer is good. But I like proper pairing. For that reason, unless the view need to be notified when it's not even seen, I usually add notification at viewWillAppear and viewDidDisappear

Anonymous White
  • 2,149
  • 3
  • 20
  • 27
  • viewDidUnload is called when the view is unloaded and viewDidDisappear just when the view has disappeared. Notifications that had to be unregistered under viewDidUnload method, now, since iOS 6.0, have to be unregistered with didReceiveMemoryWarning or dealloc – Daniel García Baena Oct 18 '13 at 12:49
5

Why not just remove the observer in the DEALLOC function? And if you are using ARC, do not call [super dealloc]

If you view controller dealloc function is not getting called, then you need to discover why this is. Perhaps you have an NSTimer running on the ViewController and when you pop the view, this would cause the dealloc not to get called. Or the view is being retained else where.

Dan H
  • 191
  • 11
  • the whole point of viewDidUnload is that you can unload the view and release stuff to save memory WHILE the view controller still exists – user102008 Oct 30 '12 at 23:27
  • In iOS 6, the viewWillUnload and viewDidUnload methods of UIViewController are now deprecated.... – Dan H Oct 31 '12 at 10:01
  • Thus you shouldn't use the dealloc method. Because the object isn't ready to be destroyed yet. – bmeulmeester Nov 01 '12 at 08:42
  • He is talking about removing an observer in his initial post, if he adds the observer in the viewDidLoad, surely the best place to remove it is in the dealloc function. I have provided an example of how to do this if he is using ARC. – Dan H Nov 01 '12 at 09:02
  • 4
    If you add an observer in `viewDidLoad` (which can be called multiple times) and remove it in dealloc, you might be registered more than once for a notification. You should use `viewDidAppear` and `viewDidDisappear` to start/stop listening. – deanWombourne Nov 07 '12 at 12:38