How to remove outside UIViews from UIViewController? - ios

I have added multiples UIViews on outside of UIViewController and all views have week outlet connected. How can i Release memory of all view when pop to back ViewController.

First: Views (or other objects) on the top level of a xib should not have a weak kind of property in their corresponding view controller. Unlike view's in the view hierarchy, they don't have an owner after the xib is loaded and so they get deallocated anyway.
Now you seem to use ivars directly (why?), so I am actually not sure, but I don't think that makes a difference. Assuming Interface Builder accepts those as outlets and sets them, they're gone soon without an owner.
From that point of view, you've already saved memory...
Without knowing more about your project I can't tell, but the fact you're not asking for help on running into nil problems makes me guess you're taking ownership of these views somewhere else. To free them, you need to set whatever property (you are hopefully soon using properties for this) refers to them strongly to nil. ARC does the rest for you. Not using ARC? Start using it...
I would recommend to restructure this. Give the view controller (I guess that's some kind of FirstFlyerViewController) strong properties to the views (if you definitely need to have them outside the view hierarchy, otherwise, just add them as subviews somewhere). Use them, and once you pop the view controller and it gets dealloced (note that this is usually done by the framework and not yourself) they get freed along with it.

Related

Update UI from another controller

I would like to update my UILabel on click the button of ContainerView contains table ViewController. When I try to do this UILabel's outlets reference shows nil value exception. I am using Swift3 with Xcode8
Most probably the problem you are seeing is due to the fact that the view that owns this label on another view controller is still not loaded.
This happens often, basically because views owned by a view controller are instantiated in a lazy manner, this means that they are loaded only when required.
To fix that before setting the value on the label, just preload the view by doing something like.
_ = another_viewcontroller_instance.view
In this way you are forcing the destination view controller to load the view and creating all the necessary connection on the xib.
Even if this fix works, this is not a good way to deal with this kind of pattern (sending info from a VC to another), but since you didn't gave us any further detail this is the only solution I have.

Does a UIView not require its UIViewController?

Playing around in Instruments, I noticed something I don't understand. I create a couple of UIViewControllers and add their views to another UIView:
CustomVC *vc = [[CustomVC alloc] initWithCustomInitializer:someParameter];
[mainView addSubview:vc.view];
By logging the memory address of the CustomVC in its init and dealloc, I see that vc is deallocated almost immediately, though the view remains on screen and everything works fine.
Does the UIView not necessarily need its controller? Or is something else going on that I'm misinterpreting?
A UIView doesn't/shouldn't retain its parent (the UIViewController), so if you drop your reference to the UIViewController and only keep the reference to the UIView, nothing keeps a strong reference to it and it will be released.
The weak reference in the UIView to its controller will be automatically set to nil.
Whether the UIView needs its "lost" controller to do its work is another story though, and entirely depending on the UIView.
UIView does not need ViewController by any means. What is happening is that you are probably not retaining pointer to VC. Pointer to view is retained by mainView.
Furthermore regardless wether you are using ARC or not. If you want to keep object in memory you need to have a strong(ARC) or retain property to it. Not to confuse you. It doesn't necessarily need to be your custom subclass. Lets say you are using UINavigationController. You can create a controller in app delegate for instance and push it to UINavigation controller. You dont need to keep a pointer to it as long as something does. This is very fundamental. You need to be clear on memory management I dont think I will be able to explain it here adequately. I would highly recommend you to check Stanford course on iOS development.
http://itun.es/ru/_zEGD
There should be only one UIViewController at a time. Adding a view that belongs to a viewcontroller is bad practice.
To answer your question, because of the above mentioned constraint (or design decision by Apple), the view is probably now retained by the other view controller, and released from vc.

Memory management in a custom UIViewController

I'm new with iOS development, but I'm familiar with the memory management basics in Obj-C. However, Apple's docs about custom UIViewControllers confused me a bit.
So, I have a PagingController that stores an array of EntryViewController objects. (They're all UIViewControllers.) These objects are loaded dynamically and, of course, released when appropriate. The view in PagingController is created in -loadView and stored in self.view, just as the documentation said.
Whenever I load an EntryViewController (as ctrl), I call [self.view addSubview:ctrl.view];. I also need to call ctrl.parent = self; since the target OS is 3.0 and I don't want to modify a private variable (_parentViewController). (parent is defined as #property(assign) PagingController *parent;)
Here are my questions:
Do I have to release self.view myself, or is UIViewController taking care of that?
Do I have to retain parent (the property in EntryViewController)? I assume it's pointless, since all the child view controllers are being released when the parent is unloaded.
Do I have to call [self.view removeFromSuperview] in the -dealloc method of EntryViewController? The docs said, I have to manage all of the subviews, so I'm not sure if this gets called automatically.
Or am I just confused about how to create a custom view controller in the first place?
UIViewController will take care of that
You shouldn't retain parent, set the property to assign, otherwise you're gonna have a retain cycle
The view controller will take care its view, you only need to release the other subviews you are retaining (removeFromSuperview isn't necessary)

Allocating UIViewControllers in viewDidLoad. Was this a mistake?

A colleague and I have been designing our code so that our view controller objects are being allocated within the viewDidLoad method of our controller objects. We did this a lot and the object graph seemed to come out just fine. After a while we found the need to add another layer above our current view controller hierarchy that would own, allocate, and release our previous parent view controller.
This got me thinking about low memory warnings and view did load. Before, our views were always visible and thus wouldn't be released if a low memory warning occurred, but now there is a chance of that happening. If it does, it seems like when the views are reloaded, they will allocated new memory for new view controllers.
Will this cause widespread memory leaks? Or will the fact that we used retained declared properties save us, since the old controllers will be released automatically? Are there styles or conventions I should consider? Thanks for the help!
If you do create your view controllers in viewDidLoad, you should release them in viewDidUnload. True for pretty much any object, not just view controllers.
But I would not be surprised if you say "Wut!?" If your view controllers need to keep their state through memory warnings, then you don't want to release them. But it will be no better if you replace them with new ones that have fresh state.
It probably doesn't make sense to create view controllers in viewDidLoad. Create them in initWithNibName:bundle: (and release them in dealloc). The design pattern is that view controllers stay around, their views can come and go. If your subordinate view controllers have anything memory-intensive, release just that object in their viewDidUnload. Then on a memory warning, you will still free up a lot of memory, but all your view controllers will stay around in a low-memory usage state, retaining only a few flags, lists of indexes, etc., that they will need to restore their views when requested.
If you are explicitly releasing each view controller that is not needed any more you will not cause any memory leaks. Usually when you present a view controller the object that is doing the presenting will retain the controller for you, so you can release it if you don't need access to it anymore. But if you are using a UINavigationController and you are pushing new view controller's then you should be implementing the viewDidUnload method. This is straight from Apple's documentation:
After it is loaded into memory, a view controller’s view remains in memory until a low-memory condition occurs or the view controller itself is deallocated. In the case of a low-memory condition, the default UIViewController behavior is to release the view object stored in the view property if that view is not currently being used. However, if your custom view controller class stores outlets or pointers to any views in the view hierarchy, you must also release those references when the top-level view object is released. Failure to do so prevents those objects from being removed from memory right away and could potentially cause memory leaks later if you subsequently overwrite any pointers to them.
There are two places where your view controller should always clean up any references to view objects:
The dealloc method
The viewDidUnload method
If you use a declared property to store a reference to your view, and that property uses retain semantics, assigning a nil value to it is enough to release the view. Properties are by far the preferred way to manage your view objects because of their convenience. If you do not use properties, you must send a release message to any view that you explicitly retained before setting the corresponding pointer value to nil

What's the best and safest practice for releasing outlets?

The iOS documentation says that your view controllers should release (and nil, since that's good practice and actually a must for 2.x compatibility) any retained outlets in -dealloc.
The documentation also says that you should do the same for your outlets in -viewDidUnload if you want to allow them being cleaned up when the view is not visible and a memory warning was issued.
I wonder about two things:
Does this mean that I should duplicate all my outlet releasing code? Put it all in -dealloc and in -viewDidUnload? That's a real pain to maintain and really easy to forget!
Am I guaranteed that all my outlets will be re-populated when the view is reloaded after a -viewDidUnload, including my outlets that reference non-view objects in my nib?
The ideal answer answers both questions above and if there is a distinction between which properties should optimally be released in -dealloc VS -viewDidUnload, clarifies this distinction in detail.
-viewDidUnload is strictly used for releasing IBOutlets with retain properties.
The reason for this has to do with the fact that UIViewController has a view property which it retains. That view property itself retains references to all of its subviews. These subviews are exactly what you are retaining inside these outlet properties. The problem lies in that these subviews have an "extra" retain on them.
The goal of -viewDidUnload is to clear up unnecessary memory usage. When -viewDidUnload is called, the view property has already been released, which releases the top level UIView along with all its subviews. Since we have retained some of these subviews however, they linger in memory, and we want to release them since they will no longer be used. New copies of these subviews will be created when (if) the view is reloaded. The properties are also set to nil, strictly so we don't have pointers pointing to deallocated memory.
In -dealloc all retained properties and instance variables should be released. In the case where the -viewDidUnload just executed, you will be sending a harmless [nil release]; to the IBOutlet retained properties you just set to nil.
To add to the excellent answers:
With the Apple LLVM 3.0 compiler (and ARC enabled), the need for -dealloc disappears (or at least, the need to release your outlets in it), leaving just -viewDidUnload to deal with. As a result, no more duplicate code.
Nick answered the part 1 of the question perfectly so I skip to part 2 right away.
You are guaranteed, indeed! When your view gets reloaded from a nib file, everything on that nib file gets reloaded. There is not method to partially load a nib file's contents so if that nib gets reloaded, everything inside will get reloaded, too. But everything loaded from a nib has an autorelease on it. So you have to retain them. If you have Outlets which retains these freshly loaded classes and you connected those Outlets as outlets on nib, you are good to go. On a view controller example controller itself is the file's owner of that nib, view is the root element on nib, view being retained by file's owner outlet "view", all other child elements retained by view itself. If you have multiple root elements or elements that root view does not retain then you have to be sure there is outlets for this elements to retain them if nib loading by system automatically, if you are loading nib by a method then you must be aware all those classes are autoreleased when they arrived to your code.
Simply views are classes too and when a nib file gets loaded, everything inside it gets loaded, not some part of it. It is your responsibility to manage outlets.

Resources