To nil out outlets in a custom UIView's dealloc under ARC? - ios

Usually in a UIViewController subclass, I nil out all outlets in viewDidUnload. But in my custom UIView, should I nil out those outlets (defined in my custom UIView) in dealloc instead? Does ARC perform these actions automatically?

No, still do it in viewDidUnload to get them out of memory as fast as possible.
ARC means you don't need to do it anywhere but it's still a bit more efficient if you do.
Though you don't ever need to nil properties in deadlock when using arc in any of your classes.

Related

Do system object delegates in ARC need to be set to nil?

An app crashes sometimes with error objc_object::release().
The Apple Developer Technical Support mentioned this:
Remember that you should always do something like _tableView.delegate
= nil; in your -dealloc methods, even if you are using ARC. For compatibility reasons system objects use unsafe_unretained
references to implement delegation, instead of the preferred modern
replacement weak.
Does that mean that I have to set the delegates of system objects to nil when the view controller is about to be released?
class MyViewController: UIViewController {
deinit {
tableView.delegate = nil
tableView.dataSource = nil
}
}
I always assumed UITableView and similar standard objects are using weak references to their delegates?
Update:
It seems that the example by the Technical Support was outdated as UITableView has already been updated to a weak delegate. However not all delegates have been updated, e.g. the AVAudioPlayer.delegate is still unowned(unsafe). It seems that Apple is gradually updating delegates to be weak.
So as to whether a delegate has been set to nil manually can simply be determined by inspecting the delegate declaration in Xcode. If it is weak, don't bother.
Yes you should set these delegates to nil.
As suggested by the name, unsafe_unretained references do not retain your view controller so there's no retain cycle or memory leak here. However, unlike weak, these references will not be set to nil automatically when your view controller is deallocated. In most cases this is not a problem as your view controller will outlive its views, or at least be deallocated at the same time.
Unfortunately there are a few cases where UIKit may have also temporarily retained the view. This can allow the view to outlive the view controller and attempt to call delegate methods on the deallocated object resulting in a crash.
The easiest way I know of to see this in action is to dismiss and deallocate a view controller which is a delegate of a scroll view (or one of its subclasses like UITableView) while the scroll is still scrolling (e.g. from a strong swipe gesture over a long list of items). The scroll view will then attempt to call delegate methods (like scrollViewDidScroll) on the deallocated controller.

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.

Is it possible that a weak reference might be garbage collected while I am using its parent in IOS?

Say I have a parent UIView. This UIView has a weak pointer to a subview UIImageView. If UIView is currently displayed on the screen, is it possible for the image view to be garbage collected since the parent UIview only has a weak reference to the UIImageView?
FYI UIview and UIImageView would both be on the screen
This UIView has a weak pointer to a subview UIImageView
Stop. If the UIImageView is a subview of the UIView, then the UIView has a strong pointer to the UIImageView. End of story.
In other words, a view retains its subviews. As long as the subview is a subview, it cannot vanish in a puff of smoke.
Now, on the other hand, if you remove that subview, then you have to worry about its memory management or it might vanish in a puff of smoke.
You use 'weak' property on subviews when they're expected to be created and directly added to a view subviews hierarchy : UIView addSubview: already keeps a strong reference to the view.
if your view is a weak property of a UIViewController, you typically create if from NIB, or in -(void)viewDidLoad. If the controller's view is discarded because not needed anymore, your subview will be too.
When you add a subview to your view, it will, by definition, maintain a strong reference to that subview. That's just part of the addSubview internal process of maintaining view hierarchies. The view will keep this strong reference to its subviews until that subview is manually removed (e.g., via removeFromSuperview) or if the superview, itself, is removed (e.g. you dismissed its view controller).
These strong references that views internally maintain on their subviews should not be confused with the weak references that you (or IB) might add to your view or view controller subclass .h file. Those weak references are just providing you a convenient way of referencing the subview or control. The fact that your .h file has a weak reference to the the subview, such as an IBOutlet for your benefit, doesn't alter the fact that views automatically already have a strong reference to their subviews behind the scenes as part of the overall view hierarchy.
So, a subview, such as an image view will only get deallocated when its last strong reference is removed (or in non-ARC language, when the retain count falls to zero). If you've added the image view as a subview, it won't get deallocated until that strong reference is eliminated (i.e. the image view is removed from it's superview, or the superview, itself is removed). Obviously, if you're maintaining other strong references to the control, those would have to be removed, as well, for the subview to be released.
A caveat: If you're not using ARC, i.e., you're doing manual reference counting (e.g. manually calling release and autorelease), it's certainly possible for you to make a programming mistake and "over release" the image view, thereby letting the retain count fall to zero, and thus allowing it to be deallocated prematurely. But given that you're referencing weak properties in your question, you must be using ARC, so this observation is moot.
There are other situations in which sloppy use of weak variables can cause problems, but I hesitate to elaborate unless you tell us that the subview is not showing up at all.
(By the way, you mention garbage collection (GC) in your question, but I assume the real question was "is it possible that my subview might be deallocated while ...". Obviously, iOS doesn't have GC. But I assume the real question is whether your subview might be deallocated while it's still present on its superview.)
If the UIVIew has the UIImageView added to it the reference will be incremented by that action wouldn't be released until it was removed from the view.
Without knowing why you asked this I would also say that I don't think there would be any harm in having a string reference to it because at the point where the UIView is cleaned up it would also dereference the the uiimageview and it would be released then.
Also I know you said garbage collected but iOS doesn't have garbage collection. I know what you mean though

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.

Should IBOutletCollections be set to nil in UIViewController viewDidUnload?

My UIViewController class has an IBOutletCollection containing several IBOutlet objects. I am aware of the need to set retained outlets to nil in viewDidUnload, but do I also need to set the IBOutletCollection to nil? Or should it be released instead in dealloc? Or left alone altogether?
You need to set your outlets to nil in viewDidUnload in order to make sure that as much memory as possible can be released by the view controller when it receives a memory warning. In response to the memory warning, the view controller releases its view in order to free the memory the view (and all its subviews) is using. If you fail to release those outlets that you are retaining/holding a strong reference to, the subviews referenced by those outlets will not be destroyed and their memory won't be freed.
So yes, you should also set the property of an outlet collection to nil in viewDidUnload.
This requirement is independent of the responsibility to release all your retained ivars/properties in dealloc.

Resources