iOS: destroy subviews in viewDidDisappear? - ios

I have a UINavigationController with a UIViewController pushed onto it. In my viewControllers view, I have two subview UIScrollViews. I recreate these scrollviews every time in the viewWillAppear method in my viewController and add them as subviews to my viewcontroller's view. I am using ARC, should I be destroying the two scroll views in viewDidDisappear method? What is better practice for memory usage.
EDIT: I did some investigation, and without removing the scroll views and setting them to nil in the viewDidDisappear method, they are not released. The viewcontroller's view gets an increasing number of subviews as viewWillAppear is called. As I mentioned in the comments, I never deallocate my main viewcontroller. It always stays on the navigation controller's stack. Why must I manually release the scroll views?

It may not be necessary to do anything at all. If your UIViewController is removed from the screen and is then being deallocated, it will automatically deallocate its view hierarchy (including subviews you have added). An easy way to check for this is to override the dealloc methods of the classes you're interested in (using an ObjC Category method added to the class), and log a message to indicate they've been removed.

Related

UIViewController subviews existance invariant

At what point in the UIViewController lifecycle is the subview property of self.view guaranteed to be populated with all the correct views? Note: I don't care about if they're laid out or not, just that they exist in the subview array. WWDC videos say that loadView, viewDidLoad, and init all don't come with that guarantee but viewWillLayoutSubviews is also late in the game.
The task I'm trying to perform in this instance is localization. In a common view controller class, I want to loop through all the subviews, see if they have a custom attribute set that identifies what localized string key is attached to that view, and then recurse through all that views subviews until the bottom of the view hierarchy is reached. Layout isn't important in this instance, just that the subviews are populated in the view controller.
At what point in the UIViewController lifecycle is the subview property of self.view guaranteed to be populated with all the correct views
The earliest point implemented by most apps is viewDidLoad. At that point you are guaranteed that self.view exists along with all the subviews from the storyboard, and that any outlets hooked up to this view controller from the storyboard have been populated.
I don't care about if they're laid out or not, just that they exist in the subview array
Exactly so. self.view and its nib-loaded subviews exist at this point, but their layout has not yet taken place and their frame is not necessarily correct. You don't care, so viewDidLoad is fine for your purposes.

IOS where to remove subviews programmatically in ViewController

I'm quite new to IOS so I'm sorry if my question is obvious.
I have set a ViewController's view in storyboard which contains other subviews.
In viewWillAppear I update these subviews depending on the object I passed to this ViewController. This object can have nil attributes and in this case I want to remove these subviews.
What is the right place to remove these subviews and is there a difference in terms of efficiency?
viewDidLoad
viewWillAppear
or viewWillLayoutSubviews ?
and will the constraints set to these removed objects also be removed?
Thx
The constraints will definitely be removed. However, it is possible to save the constraints in an array and add them back again in the future.
I would suggest making changes to the views( orientation, visibility, geometry ) in the viewWillLayoutSubviews method. You wouldn't want to do anything expensive in the ViewWillAppear method, because at that point the view is ready to be displayed to the user and it could impact how quickly the view appears to load for the user.
If you are using Storyboard and ARC do not worry about removing your views, conversely, if you are very interested to keep your memory under very tight control then do not use Storyboard and remove ARC.
What you refer to subviews are not subviews, the methods you listed are not UIView methods, and instead are UIViewController methods. However, if you have UIView objects that you are trying to remove, then those will also be handled for you. If you want more tight control, then declare them as public ivars, wrap them in #autoreleasepool {}, and set to nil in viewWillDisappear: or other method, or via delegate or notification pattern. It's relative to what you are doing and your conditions.

viewDidUnload versus viewDidDisappear

I don't understand when I should implement something in viewDidUnload versus viewDidDisappear. What's the difference between the two?
For instance, I'd like to send an NSNotification when the view controller is removed from the view hierarchy. Between these two methods, does it matter where I post that notification from?
https://developer.apple.com/documentation/uikit/uiviewcontroller
This is with reference to apple's documentation:-
viewDidUnload:-
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.
viewDidDisappear:-
Notifies the view controller that its view was removed from a view hierarchy that is everytime view dissapears or move to other view.
viewDidDisappear is called every time when the view is disappears or you go to other view and viewDidUnload is called when the controller’s view is released from memory. (Deprecated in iOS 6.0. Views are no longer purged under low-memory conditions and so this method is never called.) see the reference.

In iPad DetailView situation, viewDidUnload not being called

I set up a detail view, do I have several Nib files that get loaded depending on what item is selected in the root view controller's table.
What I've discovered is that for the Nibs' classes, viewDidUnload is never called, whereas viewWillDisappear is called and dealloc of course is also called.
Anybody know why this would be?
Thanks.
I believe viewDidUnload isn't normally called when a view disappears from view. The reason for this is because dealloc will typically take care of all the memory dumping, so it doesn't need to call viewDidUnload first.
I think an example would help identify when viewDidUnload is called. Let's say you have a UINavigationController and you've pushed on a new view. This new view is very heavy on memory usage, so the app tries to shore up some resources. It does this by seeing if any Views are loaded that aren't currently on the screen. If so, it calls viewDidUnload where ideally you remove things that you built in loadView or viewDidLoad. Then when you go back to that view, it calls loadView or viewDidLoad again to re-build what it dumped off in viewDidUnload.
But if it doesn't need to free up memory to show your detail view, it won't call it in the normal processing of it. That's why viewWillDisappear is called (and dealloc) but never viewDidUnload.
From Apple's documentation:
When a low-memory warning occurs, the UIViewController class purges
its views if it knows it can reload or recreate them again later. If
this happens, it also calls the viewDidUnload method to give your code
a chance to relinquish ownership of any objects that are associated
with your view hierarchy, including objects loaded with the nib file,
objects created in your viewDidLoad method, and objects created lazily
at runtime and added to the view hierarchy. Typically, if your view
controller contains outlets (properties or raw variables that contain
the IBOutlet keyword), you should use the viewDidUnload method to
relinquish ownership of those outlets or any other view-related data
that you no longer need.
UIViewController Class Reference

viewWillAppear versus loadView for building view hierarchy

I'm constructing my view hierarchy through code and would like to know if it's better to create the entire hierarchy in loadView, when the view is requested from my controller, and then animate the views onto the screen in the viewWillAppear method, or if it's better to keep things simpler but potentially require more freeing and allocating of memory by building the entire hierarchy in viewWillAppear.
My understanding is that the controller calls loadView to create the view the first time it needs it, then keeps it around as long as it can so that you can leave and return to this controller and animate in the views, but not need to recreate and attach them, via viewWillAppear.
Basically, I'm finding it messy to be separately allocating the views in loadView and then transitioning (and sometimes updating the contents within) them in viewWillAppear, and wondering if the benefits of retaining the views don't outweigh the simplicity of simply recreating them (and consequently re-initializing them and avoiding any un-reset values).
loadView is called only once at the creation and should contation everithing to create the view.
viewWillAppear:(BOOL)animated is called everytime the view is displayed. If your view was retained, you can update/set your data in this. (Your UIButtons, UILabels,... are already allocated by loadView, you just set the content here.)

Resources