I have a View Controller as part of a navigation controller stack with two IBOutlets. In viewDidUnload I free them up:
- (void)viewDidUnload
{
self.myView1 = nil;
self.myView2 = nil;
[super viewDidUnload];
}
But I still had a leak. So I stuck release messages in the dealloc for them too:
- (void)dealloc
{
[myView1 release];
[myView2 release];
[super dealloc];
}
This appears to clear the memory leak. However, I was always told that I should only release ivars that I have created using alloc, copy or new. So I'm worried about these two releases being in here. Is this right or wrong? Can someone please explain this to me because I keep getting conflicting opinions... Thanks!
If any of your #property objects are declared retain or copy, you need to release them in dealloc. This includes your outlets.
By using IBOutlet, the variables are exposed to be connected in Interface Builder and allocated when the view controller is initialized. So they have to be released and deallocated, as the view controller is unloaded and deallocated. Since most IBOutlets are retained UI* properties, this is necessary.
Assigning nils to the variables is technically not deallocating. It's simply the last state to have retain count 0, just before actually being deallocated.
Also, please note they are referenced using self. It means, the references from the view controller becomes nil, not the allocations.
So in conclusion, IBOutlet properties must be released in dealloc()
(Though I am quite confident, someone else may provide 100% correct answer for this.)
The basic, safe pattern is
declare ivar
declare IBOutlet property for ivar
release property in dealloc
only reference property, never ivar
The xib sets the property, which release whatever might have been there first.
I'm a bit confused why that leak was there though. Setting the property to nil should release the old reference. Perhaps viewDidUnload wasn't even getting called? Are you sure you even need viewDidUnload?
Related
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'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.
Should the Variables with the #property nonatomic and retain be released explicitly.
#interface MyScreenViewController : UIViewController <UIWebViewDelegate> {
UIWebView* greetingView;
}
#property(nonatomic, retain) IBOutlet UIWebView* greetingView;
- (void)dealloc {
[greetingView release];
}
Is release in delloc method Required ???
Ofcourse. YES you should release your properties with retain,copy and don't for assign. You set the property to Nil in viewDidUnload.
- (void)viewDidUnload {
[super viewDidUnload];
self.greetingView = nil;
}
- (void)dealloc {
[greetingView release],greetingView = nil;
[super dealloc];
}
Refer memory management in UIViewController Class reference: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewController_Class/Reference/Reference.html
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 3.0, this method was the only way to release additional memory associated with your custom view controller class but in iOS 3.0 and later, the viewDidUnload method may be a more appropriate place for most needs.
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.
Yes, you should release it, because it is a retained property. Anything property that is retained (or copied) should be released by the same class (if it is assigned, it doesn't need to be released).
Retain is basically like a class saying, "I am going to be using this other class, so keep it around in memory." dealloc is where the class that said that is, itself, going to be removed from memory. So if the class that needed your retained property is about to go away, that object itself should be deallocated, too.
Otherwise it is just going to sit there in memory, when nothing else in the program needs it. And if that kind of thing keeps happening, you will run out of memory.
(Also, make sure you that you call [super dealloc] at the end of of your dealloc method.)
I have defined a property in my viewcontroller as follows
#interface QuestionAnswerViewController : UIViewController
{
Question *question;
}
#property (nonatomic, retain) Question *question;
and I synthesized the property in my .m file
#synthesize question;
Will there be any issues if I don't set 'self.question = nil' in my viewDidUnload method?
- (void)viewDidUnload
{
[super viewDidUnload];
//Any issues if I don't set this?
self.question = nil
}
Reason why I am asking this is because the 'question property' is actually passed in from another view controller. I realised that in the case of low memory, my view controller's view will be automatically unloaded, so if I set self.question=nil, I will lose the information on the current page (self.question becomes nil). Just want to confirm the repercussions in not setting a synthesized property to nil and if there are any other ways to prevent this from happening.
You only release IBOutlets and those items that you can easily re-create on viewDidUnload.
If the view is unloaded, say automatically by a memory warning, any sub-components that are do not have their retains reduced will not be unload and less memory will be reclined that could be. This ultimately may cause your app to be terminated due to insufficient memory.
In iOS IBOutlets are retained so setting their property to nil releases them. Since the view that contains them is being unloaded these subviews have no reason to live, when the system reloads the view the subviews will also be reloaded at that time.
The implication is that those retained subViews of the mainView since they usually have a retain count of 2 for those declared as retain, one when it was set for the first time, and another one when it was added as a subView, when the superView is released the retain count will still be one.
I've found on Apple documentation pages an example in which they deallocate the memory as follows:
- (void)viewDidUnload
{
self.mapAnnotations = nil;
[super viewDidUnload];
// Relinquish ownership of anything that can be recreated in viewDidLoad or on demand.
// For example: self.myOutlet = nil;
}
- (void)dealloc
{
[mapAnnotations release];
[super dealloc];
}
I was wondering why
they first set mapAnnotation to nil in viewDidUnload and then they release in dealloc method and
why they refer using to mapAnnotation with and without self.
This is the downloadable example by the way: MapCallouts Example
The question you should be asking is: when is viewDidUnload called?
In short it's called in low memory situations where you don't want to deallocate the whole controller, i.e., when you don't want dealloc to be called.
You can think of viewDidUnload as the opposite of viewDidLoad of loadView whereas dealloc is the opposite of init. (In practice it can get a bit more complicated than that of course.)
viewDidUnload can be thought of as the opposite of viewDidLoad. It is called in cases where the view is unloaded due to memory warnings, but the view controller is not actually deallocated.
It allows you to release memory that is only relevant when the view is loaded, and therefore allows you to free up memory in these low memory conditions.
As for the difference between the two releases, one using self and one not:
In the viewDidUnload method, the variable is being set to nil via it's accessor methods. The variable has been declared as a property, likely with the retain attribute. When assigning nil via a property, it's functionally the same as the following code:
- (void)setMyObject:(MyObject *)object
{
[myObject release];
myObject = [object retain];
}
So if you're passing nil to that method, you'll be releasing the old instance and assigning nil to the variable. Assigning nil after releasing is considered good practise to prevent any possibility of trying to dereference a dangling pointer.
In the dealloc method, the variable is accessed directly, as opposed to via an accessor method or property, and is released. There is not really any need to assign nil at this point because the owning object will be deallocated and will not be accessing any of its pointers, making the possibility of dereferencing a dangling pointer very low.
(1) This is done so you can let go of references so the system can deallocate resources in low memory situations. It is the reciprocal of viewDidLoad:
(2) If you refer to self using dot notation, you will maybe create an object that is the implementation detail of the property. Using the name ensures that you release the object itself, and not the object returned by the property. In the first example, in the case of an outlet, assigning nil with the dot notation (self.) will decrement the retain count of the retained property.