I was reading a book, which suggested that declaring my IBOutlets as weak should take care of the issue when my app gets low memory warning. e.g., I would not need to set these outlets to nil now in the viewDidUnload method anymore.
I also heard in iOS6 viewDidUnload is deprecated and instead didReceiveMemoryWarning is called.
Anyway, how shall I go on, shall I declare my IBOutlets as weak, and "forget" about implementing didReceiveMemoryWarnings and viewDidUnloads?
Not all IBOutlets should be made weak. Recommendation from Apple docs (Resource Programming guide)
Outlets should generally be weak, except for those from File’s Owner to top-level objects in a nib file (or, in iOS, a storyboard scene) which should be strong. Outlets that you create should therefore typically be weak, because:
Outlets that you create to, for example, subviews of a view controller’s view or a window controller’s window, are arbitrary references between objects that do not imply ownership.
The strong outlets are frequently specified by framework classes (for example, UIViewController’s view outlet, or NSWindowController’s window outlet).
Example:
Top level objects in your XIB should be declared strong, any other subviews/controls should be made weak properties.
#property (nonatomic, weak) IBOutlet MyView *viewContainerSubview;
#property (nonatomic, strong) IBOutlet MyOtherClass *topLevelObj;
Using ARC weak lifetime qualifier has its own advantages(Refer Apple docs) because,
__weak specifies a reference that does not keep the referenced object alive. A weak reference is set to nil when there are no strong references to the object.
So you need not worry about setting the IBOutlets nil, its lifetime is automatically bound by its top level instance.
didReceiveMemoryWarning should be implemented to clear any recreatable resources which are hogging the memory. When you receive the didReceiveMemoryWarning call, it should be used to release non-critical resources that are used ex: custom data structures, webservice response used to populate the UI etc. The non-criticality of any resource needs to be decided by the developer.
It is advisable to use IBOutlet as weak. When you declare them as strong, in case of low memory condition, you might need to handle to clear them in viewDidUnload method.
However there are many more objects apart from Outlets which can also be removed from memory in case of memory issues. So, if the program is having outlets as weak, you just need to consider the cached data objects and noting else.
Views are no longer automatically unloaded on memory warnings since iOS6. This doesn't mean that memory use is no longer of any concern of course, you can't just 'forget' about it.
IBOutlets should generally be weak, since they are (directly or indirectly) 'owned' by the viewcontroller's view. And usually you want their lifetimes to be the same as their parent view.
You should still try to clear as much memory as possible in didReceiveMemoryWarning. (memory of assets that are not currently used and can be recreated of course)
According to Apple's documentation:
Memory is a critical resource in iOS, and view controllers provide built-in support for reducing their memory footprint at critical times. The UIViewController class provides some automatic handling of low-memory conditions through its didReceiveMemoryWarning method, which releases unneeded memory.
Prior to iOS 6, when a low-memory warning occurred, the UIViewController class purged its views if it knew it could reload or recreate them again later. If this happens, it also calls the viewWillUnload and viewDidUnload methods to give your code a chance to relinquish ownership of any objects that are associated with your view hierarchy, including objects loaded from the nib file, objects created in your viewDidLoad method, and objects created lazily at runtime and added to the view hierarchy. On iOS 6, views are never purged and these methods are never called. If your view controller needs to perform specific tasks when memory is low, it should override the didReceiveMemoryWarning method.
Therefore, no need to set any 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, in case 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.
Related
Hi I am a newbie to iOS programming. I know what a strong and weak reference is. But I get confused which type of reference to use when I have to deal with outlets. After going through the documentation which states that
Outlets should generally be weak, except for those from File’s Owner to top-level objects in a nib file (or, in iOS, a storyboard scene) which should be strong.
So what I understood after going through the above statement is that the Outlets that we create should typically be weak by default.
But while studying some tutorials I have come across the code where people have declared an outlet as strong reference. For example consider the following code :
#interface AboutViewController : UIViewController
#property (nonatomic, strong) IBOutlet UIWebView *webView;
#end
The code :
#property (nonatomic, strong) IBOutlet UIWebView *webView;
says that our AboutViewController has an UIWebView object.
But why we need a strong reference here for the UIView object?? As the document states shouldn't this be an weak reference ?
Also please explain in the documentation statement which I have quoted above what does the File’s Owner to top-level objects mean?.
I have gone through many of the similar questions on this website but none of them helped me to clear my doubt. So please help. Thanks in advance :)
What to use for non top level GUI elements - strong or weak - depends on how you are going to use their outlets. If you have a weak reference
#property (nonatomic, weak) IBOutlet UIWebView *webView;
then after calling method
[webView removeFromSupeview];
your webView will be nil and it will be impossible to restore UIWebView just by adding
[self.view addSubview:webView];
If this is appropriate for you - it is better to use weak because you will free webView's memory when you do not need it.
On the other hand, in case of a strong reference after
[webView removeFromSupeview];
webView will still have referenceCount > 0 and webView will be deallocated only if owner will free it explicitly
self.webView = nil;
or in the owner's
- (void)dealloc
together with the owner itself.
Usually there is no difference if you have static GUI. If you want to remove (not hide) some views add be able to add them later - strong references should be used.
Top level objects should be retained strong. Like
#property(nonatomic,retain) UIView *view;
in UIViewController.
It usually doesn't hurt to use a strong reference in place of a weak one in the case of outlets like this. And in some cases, you do need a strong reference.
The idea is that something has to keep a strong reference to the object at all times or it could vanish. If the object is a view that is a subview of another view, then that superview will keep a strong reference to it and so you can use a weak reference. But, if you're going to do something else with that view, such as remove it from it's superview for some reason (maybe to reuse it elsewhere, or something), then you'll want to use a strong property so that there's always something holding it strongly.
Regarding the File Owner issue, that's because the top level object (most likely a view) does not have a superview holding on to it, so you need to use a strong property so that you're holding on to it.
The simple answer is that unless you are supporting iOS 5, outlets should always be strong.
The purpose of weak outlets was so that in iOS5, if the system unloaded the view controller's view to save memory, any outlets pointing to subviews would be automatically released.
In iOS 6 and later, the system never unloads the view controller's view (viewDidUnload is never called) because Apple found a way to release most of the memory used by a view without releasing the view itself.
Consequently, the outlets in a view controller will never normally need to be released until the view controller itself is released, at which point ARC will clean up all the outlets anyway.
So just use strong for all your outlets and you won't have to worry about obscure bugs or compiler warnings due to using the wrong reference type.
Quoting from Apple's Resource Programming Guide,
Each time you ask the NSBundle or NSNib class to load a nib file, the underlying code creates a new copy of the objects in that file and returns them to you. You need to ensure that you maintain the new object graph as long as necessary, and disown it when you are finished with it. You typically need strong references to top-level objects to ensure that they are not deallocated; you don’t need strong references to objects lower down in the graph because they’re owned by their parents, and you should minimize the risk of creating strong reference cycles.
In case of framework classes like UIViewController the top-level object for the NIB file is the view property. If you check in the documentation it is declared as retain(similar to strong).
#property(nonatomic, retain) UIView *view
So any subviews to this container view should be automatically owned by it. If you now declare these subview outlets as strong they will create a strong cycle and cause memory leaks when the framework tries to cleanup the container view. To avoid these strong cycles all subviews (or non top level objects) should be declared as weak properties.
When can you declare IBOutlet's as strong
Outlets should be changed to strong when the outlet should be considered to own the referenced object:
As indicated previously, this is often the case with File’s Owner—top level objects in a nib file are frequently considered to be owned by the File’s Owner.
You may in some situations need an object from a nib file to exist outside of its original container. For example, you might have an outlet for a view that can be temporarily removed from its initial view hierarchy and must therefore be maintained independently.
You need to check in your code if webView object qualifies for case2 as above. If not the tutorial has got this one wrong and it actually should be weak.
Hope that helps!
I have read several Q&A and documentations which state that we should use weak for IBOutlet unless it's top level objects from File's Owner.
But if I still use strong/retained, is there any major downside, or is it just redundant because the subview is already retained with addSubview:?
Note: please do not copy definition of weak / strong here, I don't need that, I want to see real world cases where using strong for IBOutlet could cause problems. Thanks.
With MRC, if you use retain, you will have to release the memory by yourself.
With ARC, if you use strong and the system requests memory from your app (= your view will be unloaded), you will have to release the memory by yourself (note that the controller would be still be active, so no dealloc called there)
For most outlets, weak/assign is appropiate because you don't need to care about releasing the memory.
Exceptions:
IBOutletCollection must be strong/retain. The collection (NSArray) is not retained by the view hierarchy.
You add/remove views dynamically. If you want to remove a view from your view hierarchy and use it again later, the view must be retained somewhere, otherwise it gets deallocated at the time of removal. However, note that you can always retain it in code at the time of removal.
I will mark this as "accepted" until someone provides a better answer.
Apparently the only downside is that when your view receives a memory warning, it would unload the view, and optimally all the subviews should be released. But since your controller still retains them if you use strong, you will have to nil them out manually in viewDidUnload.
From iOS 6, view is not unloaded upon receiving memory warning, so this becomes inconsequential. From a practical point of view there is no major difference between using weak or strong for IBOutlet afaik, unless you have to unload your view manually in your application.
An application that I am working on, that uses ARC and needs to support iOS 4.3 and iOS 5, declares every outlet as #property (strong, nonatomic) IBOutlet in the .h file.
e.g.
// myClass.h
#property (strong, nonatomic) IBOutlet UITextView *myTextview;
I know that with ARC only properties which do not hold a strong reference to an object are released.
As a result, the App relies on - (void)viewDidUnload to set the property myTextview to nil.
i.e.
// myClass.m
- (void)viewDidUnload
{
[super viewDidUnload];
self.myTextview = nil;
}
I know, from Apple's Documentation, that Outlets should generally be weak except those from File's Owner ( i.e. A Runtime Object that owns the contents of the iOS Storyboard scene) to Top-Level Objects (my rule of thumb is to use anything that appears in the window with File's Owner, First Responder and View).
Anything I add to the view will be a subview and thus is retained by it's direct superview, meaning a weak reference should be used.
I am also aware that - (void)viewDidUnload is deprecated in iOS 6 and is not called.
1st Question : What are the issues with taking the approach of declaring every outlet as a strong property and setting it to nil in viewDidUnload, apart from the fact that viewDidUnload is deprecated in iOS 6?
My intuition tells me that it is because situations arise where you can set a pointer to nil, before viewDidUnload is called. So you should, to free up memory on the heap. Is there a noticable performance change if this is the case?
2nd Question : Should I go back throughout the project and change strong to weak? Why? Is it worth the time?
3rd Question : If I was to declare the property in a class extension, to 'hide' it, how does this affect my rule of thumb for deciding on when to use strong or weak.
I know there are many threads here that discuss this issue. But many I've found are out of date, and do not address this issue directly. Thanks.
First, a few of your presumptions need addressing:
I know that ARC only releases properties which do not hold a strong
reference to an object. As a result, the App relies on -
(void)viewDidUnload to set the property myTextview to nil.
Not quite. ARC never retained weak properties in the first place. As for strong properties, ARC still releases them, but not until dealloc is called.
viewDidUnload was never used to prevent leaks. It was essentially an optimization, and one that Apple decided was no longer worth the trouble. To understand, consider the standard lifecycle of a pre-iOS6 view controller:
1. Allocated
2a. View Loaded
2b. View Unloaded
3. Deallocated
Where 2a and 2b could be repeated any number of times. For example, a view controller at the bottom of a navigation stack (its view being hidden) could have its view unloaded in low memory situations. It would then be reloaded the next its view became visible.
The method was essentially saying "Hey view controller programmer, we're running low on memory, and nobody can see me anyways, so I'm releasing my view. If you could do the same for your strong properties, that would be great."
That process had subtleties and was generally confusing. As a result of the tediousness, Apple deprecated it. Views are no longer unloaded, so there's no point in implementing it. The key point is that all your strong properties will still be released in ARC's dealloc method.
I know that Outlets should generally be weak...
Why do you know that? There's nothing special about outlets. The 'IBOutlet' keyword is really just for Xcode's benefit when designing things with its visual tools. It has no effect on the compiled code. So, when thinking about strong vs weak outlets, use the same considerations that you do for any other property, namely "do I need this to exists, or am I okay with it disappearing on me?".
What are the issues with taking the approach of
declaring every outlet as a strong property and setting it to nil in
viewDidUnload, apart from the fact that viewDidUnload is deprecated in
iOS 6?
There are no issues with that. If you want your properties to exists as long as your controller, then use strong. viewDidUnload has nothing to do with this. On older iOS versions, you could release strong outlets in viewDidUnload if you want.
Should I go back throughout the project and change
strong to weak? Why? Is it worth the time?
Again, just use whichever qualifier makes sense for your use case. You're almost always safe using strong for you outlets.
If I was to declare the property in a class extension, to 'hide' it,
how does this affect my rule of thumb for deciding on when to use
strong or weak.
There's no difference.
1st question: The outlets are subviews of the main view which is a property of the view controller. If you declare them as weak, they have a retain count of 1, since they are subviews. If the view is released, they are also released. If you declare them as strong, they have a retain count of 2, since they are subviews, and strong properties of the view controller. So they are only released when the view controller is released (which releases also its view and its subviews). To my understanding, the difference is that when the view of a view controller is released, e.g. when it is not presented and memory is low, the outlets still allocate memory when they have been declared as strong.
2nd question: I believe in most circumstances it does not matter.
3rd question: I believe if you declare properties in a class extension, the simply belong to the class, and thus there is no difference in handling them compared to "real" class properties.
My approach would be to make sure not to declare properties as strong that could result in retain cycles, what happens, i.e., if you declare a delegate as strong.
I am developing an iPhone app with ARC option enabled. i am creating IBOutlets in .h files which are connected from file owners icon to .xib elements.for eg.
IBOutlet UIButton *bt;
#property(nonatomic,retain)IBOutlet UIButton *bt;
in .m file, i am doing
#synthesize bt;
Is there a need to explicitly set bt to nil in viewDidUnload method? i.e. self.bt = nil; in viewDidUnload?
Also, do I need to write dealloc method with ARC option enabled? When should I make IBOutlets elements as strong and weak references with ARC enabled?
There's a difference between the need to put your outlets to nil in viewDidUnload and dealloc
Having ARC means you don't need to write that in your dealloc method (it gets done automatically), however the viewDidUnload method serves another purpose, and it is to free memory that the application isn't using when a memory warning occurs.
dealloc is still needed in some cases, for example, when your class is registered for a notification, or when your class is someone else's delegate and you don't want some glitchy callback giving you a bad access
When you get a memory warning, all the UIViewControllers not being displayed will unload their view and call that method to free up memory. If you are still retaining outlets (like buttons, tables and etc) they will not get released, thus, killing the purpose of the viewDidUnload method.
When using ARC there is no need to use modifiers like retain or copy, for example. That kind of memory managment is done automatically using the strong and weak modifiers.
You also don't have to worry about writing dealloc methods.
strong is kind of the equivalent of retain, so you should mark your outlets with it
#property(nonatomic, strong) IBOutlet UIButton *bt;
That's the way interface builder creates them by default.
I won't go into detail about their semantic differences, but you should really have a look at Apple's guide on transitioning to ARC if you want to know what's going on and read about the specifics of strong and weak modifiers.
EDIT:
Sorry, interface builder creates outlets with weak by default.
EDIT 2:
strong and retain are indeed 100% identical. (thanks to #Adam)
EDIT 3:
You set your pointers to nil to avoid getting any message sent to deallocated instance or BAD_ACCESS_EXCEPTION errors.
If you are actually using ARC, you should make your outlets (nonatomic, weak) instead of (nonatomic, strong). By using the weak zeroing pointers, what the compiler does is automatically set your outlets to nil when nothing else references them.
So, summing up, if you don't use weak properties, you should set your pointers to nil.
I'm still learning iOS development and have been working with various tutorials and books. Some pre-ARC, some with ARC.
In some cases, we're taught to release all of the properties and subviews of a ViewController on viewDidUnload but in some cases I've been told this is no longer required.
Can someone give a definitive answer? In iOS 5+, does one have to do the whole:
-(void)viewDidUnload
{
[super viewDidUnload];
self.photoViewCell = nil;
self.photoImageView = nil;
self.firstNameTextField = nil;
self.lastNameTextField = nil;
}
... or not? If so, is this only for properties that are descendants of UIView or is it for all properties of the ViewController?
Thanks
So each view has a number of owners. When that "owner count" (usually referred to as the retainCount) reaches 0, that object gets destroyed.
In iOS 5, we now have weak references, which essentially means "don't own this object".
Before iOS 5, in our header files, you'd see
IBOutlet UILabel *myLabel;
And this label was added to the XIB file's view. myLabel has 2 owners in this case: it's superview (the view in the XIB file) and the view controller (by having the IBOutlet). When viewDidUnload get's called, the view controller's view has been released, and therefore it's ownership of myLabel is gone. So myLabel at this point only has 1 owner, the view controller. So we needed to release it in viewDidLoad to make sure it didn't have any owners and so was destroyed.
With iOS 5, you will often seen this instead
__weak IBOutlet UILabel *myLabel
This is saying that we don't want the view controller to be an owner of myLabel. So the only owner is the view controller's view. So when viewDidUnload get's called, the view controller's view has already been released, and so its ownership of myLabel has also been released. In this case, myLabel now has no owners and its memory is released. There is no need for the self.myLabel = nil; there.
So with iOS 5, the recommendation is to make all of your IBOutlets a weak reference. With this, you don't even need to implement viewDidUnload, as all the memory has been taken care of for you.
But even if you are using iOS 5, if your IBOutlets aren't weak references, you'll need that code in viewDidUnload.
viewDidUnload has nothing to do with retain counting, automatic or otherwise. This method will be called when a view is unloaded due to memory pressure, which means that you should also nil (and release, non-ARC) elements of the view that you hold strong references to. Failure to do this may mean that your app does not free enough memory when under memory pressure, which can lead to it being closed by the OS.
You can use viewDidUnload to manage Memory, if your App deserves it.
But don't do a
myInstanceVariable = nil;
You loose your reference to the memory location, where the values of your variable live.
= nil doesn't free the memory. Still, your object has to be deallocated. And therefore the retainCount and retain/release are used.
If you nil your object in viewDidUnload you cannot release in dealloc! Attention!!!
If you know, what you do, you can release and nil your object in viewDidUnload.
ARC:
Using ARC, you must not release manually, even I think you can't do so. ARC takes care of that.
Simply use #properties as much as you can with with (weak/strong) attribute to let getters and setters do the work for you. You can declare #properties in your .m file either (like in a class extension).
Simple rule: strong for objects you want to own, weak for objects, you don't want to get lost in a retain cycle and hold ownership to. ARC does the rest in almost all situations. Use weak for delegates for example.
nil objects, where you are sure, you won't send them a message to, otherwise do not.