iOS 6 - viewDidUnload migrate to didReceiveMemoryWarning?
Asked Answered
F

5

33

So with viewDidUnload deprecated as of iOS 6, what do I need to do now?

Delete it, and migrate all of it's contents in didReceiveMemoryWarning, or leave it, and don't do anything in didReceiveMemoryWarning?

Frogfish answered 1/10, 2012 at 13:28 Comment(0)
E
67

The short answer is that, in many cases, you don't need to change anything. And, you most certainly do not want to simply migrate all of the contents of viewDidUnload to didReceiveMemoryWarning.

Generally, most of us do the setting of IBOutlet references to nil in viewDidUnload (largely because Interface Builder would put that there for us) and do the general freeing of memory (e.g. clearing of caches, releasing of easily recreated model data, etc.) in didReceiveMemoryWarning. If that's the way you do it, then you probably don't require any code changes.

According to the iOS 6 viewDidUnload documentation:

Views are no longer purged under low-memory conditions and so this method is never called.

Therefore, you do not want to move the setting of your IBOutlet references to nil anywhere, because the views are no longer purged. It would make no sense to set them to nil in didReceiveMemoryWarning or anything like that.

But, if you were responding to low memory events by releasing easily-recreated model objects, emptying caches, etc., in viewDidUnload, then that stuff should definitely move to didReceiveMemoryWarning. But then, again, most of us already had it there already.

Finally, if you free anything in didReceiveMemoryWarning, just make sure your code doesn't rely upon them being recreated in viewDidLoad again when you pop back, because that will not be called (since the view, itself, was never unloaded).

As applefreak says, it depends upon what you were doing in viewDidUnload. If you update your question with explicit examples of what you had in your viewDidUnload, we can probably provide less abstract counsel.

Earpiece answered 1/10, 2012 at 15:54 Comment(0)
M
61

The short answer:

Never use -didReceiveMemoryWarning for a balanced tear down as it might get called never or multiple times. If you have your setup in -viewDidLoad, place your cleanup code in -dealloc.


The long answer:

It's not easy to give a general answer, as it really depends on the situation. However, there are two important facts to state:

1. -viewDidUnload is deprecated and in fact never called starting with iOS6 and later. So, if you have your cleanup code in there, your app leaks under these OS versions

2. -didReceiveMemoryWarning might be called multiple times or never. So it's a really bad place for a balanced teardown of objects you created somewhere else

My answer is looking at the common case where you are using properties, for example:

@property (strong) UIView *myCustomView  // <-- this is what I'm talking about
@property (assign) id *myDelegate

Here you have to do some cleanup, because you either created and own the customView or InterfaceBuilder created it, but you are retaining it. Before iOS 6 you would probably have done something like this:

- (void)viewDidLoad {
    self.myCustomView = [[UIView alloc] initWithFrame:…];
}
- (void)viewDidUnload {  // <-- deprecated!
    [myCustomView removeFromSuperView];
    self.myCustomView = nil;
}

...because (again) myCustomView is a retained property, created and owned by you and so you have to take care and "release" it (set it to nil) at the end.

With iOS 6, the best place to replace -viewDidUnload and to set the retained property to nil is probably -dealloc. There's also viewWillAppear and viewDidDisappear, but these are not tied to the lifecycle of your view/controller, but the display cycle (On the other hand, the -...appear methods are perfect for un-/registering notification listeners!). So it might not be appropriate to create and destroy views before and after every display. dealloc is the only method we can be sure of to be called at the very end of the controller's lifecycle. Note that you must not call [super dealloc] if you're using ARC:

- (void)dealloc {
    self.myCustomView = nil;
}

However, if you're using viewDidLoad to do some view related setup that can be freed upon low memory conditions, the other posts showing how to deal with low memory situations are totally valid. In this case you can also use dealloc, but you have to check if your views are still there.

The Lifecycle of a ViewController

Maybe it's also helpful to look a the general lifecycle of a ViewController:

This is the lifetime of a viewController (lines in italic mean that these methods might be called multiple times):

  • init: ViewController loaded, no interface element (IBOutlet) available yet (all nil)
  • viewDidLoad: the nib/storyboard has been loaded and all objects are available. The user sees nothing yet
  • viewWillAppear: the view is about to be displayed
  • viewDidAppear: the view is on screen
  • viewWillDisappear: the view is about to go away
  • viewDidDisappear: the view just was taken off the window
  • viewDidUnload: NEVER CALLED in iOS6/7
  • didReceiveMemoryWarning: You don’t know if, when and how often this is called. Prior to iOS6 it might unload the view, after iOS6 it just purges an offscreen cache or does nothing
  • dealloc: the viewController is about to get destroyed

So, to sum it up there are various possibilities; what goes where now really depends on what was initialized where:

  • -dealloc if created in -init: or -viewDidLoad:
  • -viewWill/DidDisappear (paired with -viewWill/DidAppear)
  • -didReceiveMemoryWarning (might or might not be called)
Mcgrath answered 1/3, 2013 at 10:46 Comment(3)
+1 Good answer. BTW, with iOS 7 dynamic transitions, viewWillAppear might better be described as "the view will be (or may be) displayed" and viewWillDisappear as "the view will be (or may be) removed". With dynamic transitions, we're no long assured that viewWillAppear will be followed by viewDidAppear, nor that viewWillDisappear will be followed by viewDidDisappear.Earpiece
Also, in your myCustomView example, I hope no one ever did that, because that's only half a solution: Even in iOS 5, they'd have to do the release stuff in dealloc, too, because viewDidUnload was never called "at the end", but rather only under memory pressure where you had pushed/presented another view. viewDidUnload was never called when you just dismissed a controller, only in that memory pressure scenario. So, they wouldn't be "moving" the release of myCustomView to dealloc, but rather it would have needed to be there anyway.Earpiece
dealloc doesn't get called when any object (some kind of notifier for example) holds strong reference to this viewController!Monocyte
A
7

If you need to know if your UIViewController is dismissing you can add this code to your viewWillDisappear:

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];

    if ([self isBeingDismissed] || [self isMovingFromParentViewController])
    {
        // Do your viewDidUnload stuff
    }
}

It is not called at the same time as viewDidUnload did once in the view controller life cycle, but works in most cases for your needs!

Aribold answered 1/4, 2015 at 9:57 Comment(0)
D
1

Depends on what you do in viewDidUnload but you can use didReceiveMemoryWarning or dealloc to release data. See this.

Deactivate answered 1/10, 2012 at 14:55 Comment(4)
I agree that it simply depends upon what was in Devfly's viewDidUnload, but I'd be shocked if there's anything that needs to move to dealloc as a result of iOS 6. Generally, when we use a view controller and then dismiss/pop it, viewDidUnload is never called (it's only used in low memory situations), so hopefully there's no routine cleanup in viewDidUnload that they're not also cleaning up in dealloc! If anyone is doing this sort of stuff in viewDidUnload in lieu of dealloc, then they have bigger problems on their hands.Earpiece
You are right Rob. I think you use dealloc to remove the observers? I know iOS 6.0 automatically releases viewcontroller's memory image once it has been unloaded but if I want to perform some operation just before my view controller deallocated. For example call unsubscribe method of communication manager so that it decrement it's observers count by one. so what I do in iOS 6.0 is, subscribe observers in intiWithCoder and unsubscribe in dealloc. Is that bad design?Deactivate
This is all unrelated to this post, but in that other discussion you reference, the OP clearly didn't understand the purpose of viewDidUnload. But in answer to your question, yes, you can this sort of stuff in dealloc, but viewWillDisappear is probably better. Most importantly, if your communication manager maintains a strong reference to your view controller, then you absolutely should not try to unsubscribe in dealloc (because you'll have a strong reference cycle; dealloc will never be called). That sort of stuff must be done elsewhere, e.g. viewWillDisappear.Earpiece
Thanks @Rob. You are right but there are something that you have to do in dealloc. I can't do in viewWillDisappear or viewDidDisappear as that view presents another view!! At any time, I don't want to unsubscribe intermediate level children! While using storyboard with segue type "Modal", you get view disappear msgs when you present another view controller but you get dealloc only once when view is actually removed from the memory. I have another way to subscribe/unsubsribe in viewWillAppear/ViewWillDisapper but I want my view controller receive msgs from comm manager till it is in the memory!Deactivate
M
1

In most typical cases, this method can be used in place of the old viewDidUnload.

// The completion handler, if provided, will be invoked after the dismissed controller's viewDidDisappear: callback is invoked.
- (void)dismissViewControllerAnimated: (BOOL)flag completion: (void (^)(void))completion NS_AVAILABLE_IOS(5_0);

Swift 2017 syntax:

override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
    if (yourChildViewController  != nil) {
      print("good thing we did this!")
    }
    yourChildViewControllerProperty = nil
    super.dismiss(animated: flag, completion: completion)
}
Milore answered 5/2, 2014 at 23:40 Comment(1)
generally the best answer in 2017Wealthy

© 2022 - 2024 — McMap. All rights reserved.