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.)
Related
I'm currently working on fixing some iOS 7 display issues on a legacy app which was not built with ARC, and have run into some inconsistent behaviour with the dealloc method between iOS versions 6 & 7. I can't find any other mention of these changes in any documentation or community discussions, so I wonder if anyone here could shed some light on what's happening here?
My previous code, (which works in iOS6, looks like this):
#interface MyViewController()
#property (retain) AdHandler *adHandler;
#end
#implementation MyViewController
#synthesize adHandler = _adHandler;
- (id) initWithAdHandler:(AdHandler*)anAdHandler
{
self = [super init];
_adHandler = [anAdHandler retain];
return self;
}
- (void)dealloc
{
[super dealloc];
[_adHandler release];
_adHandler = nil;
}
...
#end
When stepping through the code in iOS 6, I've found that after the dealloc statement, [_adHandler retainCount] is still positive, and the object is still available.
In iOS 7 however, after the dealloc statement, retainCount has somehow hit zero, and the _adHandler object has been dealloc'd, and therefore my call to release causes an EXC_BAD_ACCESS.
I can fix this simply by moving my [adHandler release] call to before the dealloc call, but my question is why is this happening? Why is dealloc releasing objects that it has no responsibility for? Is there any documentation anywhere on why dealloc behaviour has changed in this way?
After [super dealloc] the instance is garbage and whatever happens is rather random and non-deterministic. As #bneely wrote, [super dealloc] must be last.
Best practice: convert to ARC.
As for retainCount, there are no guarantees what it's value may be, don't use it, it just caused confusion. In your case you destroyed the class instance by calling [super dealloc] and then expect the instance to behave as if it still exists. It can't, it has been destroyed and is now just some non-deterministic bits in memory.
You should never use retain count.
The values it returns cannot be interpreted by you in any reasonable way. Thus it's entirely expected to see different results on different iOS versions, devices, with different code bitness, etc.
On a side note, do you consider switching to ARC? The code would greatly simplify. Also note that if you're implementing a subclass of UIViewController, you shouldn't initialize it with init. Rather just declare the property and ARC will take care of its setters and getters:
#interface MyViewController : UIViewController
#property AdHandler *adHandler;
#end
// somewhere else
MyViewController * mvc = ... from nib or in some other way ...
mvc.adHandler = myAdHandler;
Now you're guaranteed no bad accesses.
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.
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.
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?