Does dealloc get called after viewDidUnload? - objective-c

A quick question, after viewDidUnload does the dealloc also get called? I am asking with regards to pickerData, it was my understanding that the variable would be released when the dealloc gets called. My reason for asking is that I have noticed in one book that the author sets pickerData to nil in the viewDidUnload. Is this harmless overkill, maybe even good practice, or is there no scenario where one would not be called without the other.
INTERFACE:
#interface SingleViewController : UIViewController {
NSArray *pickerData;
}
#property(nonatomic, retain) NSArray *pickerData;
#end
IMPLMENTATION:
-(void)viewDidUnload {
[self setSinglePicker:nil];
[self setPickerData:nil];
[super viewDidUnload];
}
-(void)dealloc {
NSLog(#"Here");
[singlePicker release];
[pickerData release];
[super dealloc];
}
#end
gary

No, viewDidUnload: is called when a UIViewController's view is released. dealloc: is only called when the UIViewController's reference count goes to zero. The author's code is good practice.
The author is using synthesized methods to set the ivars to nil, which means those ivars are sent release messages. viewDidUnload: is where you're supposed to release any objects or memory you can easily recreate. The author is essentially saying, "I don't need references to these things anymore, decrement the retain count and hopefully that will free up some memory. I'll recreate it later if necessary in viewDidLoad:."
Setting the ivars to nil will have no consequences if dealloc is called as messages to nil are handled by the Objective-C runtime.

Related

Memory management for Outlets in iOS

Hi I have this in my application : The question is, should I put self.label =nil; in viewDidUnload? If yes, why?
//.h
#interface MyClass
#property (nonatomic, retain) IBOutlet UILabel *label;
#end
//.m
#implementation Myclass
#syntesize label = label_;
- (void)dealloc
{
self.label =nil;
}
#end
Yes, you should set the label property to nil both in viewDidUnload and in dealloc. viewDidUnload is called in low memory situations which enables the app to purge unneeded memory.
Not setting it to nil in viewDidUnload will not usually cause a memory leak in, but it will prevent the app from saving memory when needed.
You should do.
viewDidUnload is called in low memory condition. So if you want to clean up call self.yourOutlet = nil also in this method. Furthermore it allows you to save extra memory for your app.
The next time (after viewDidUnload method is called) your view will be loaded into memory again (viewDidLoad will be called) and your outlet will be set up correctly.
As a rule of thumb any IBOutlets you release in dealloc, should also be released (reference set to nil like self.label = nil) in this method.
A note
You should not call self.label = nil; in dealloc. Instead do [label_ release]; as documented in Apple Memory Management Guide.
In addition, Stack Overflow search is your friend:
When is UIViewController viewDidUnload called?
When should I release objects in -(void)viewDidUnload rather than in -dealloc?
Hope that helps.
Edit
if you not use ARC (I think not) you should call also [super dealloc]; like the following:
- (void)dealloc
{
[label_ release];
[super dealloc];
}
You should. Although not necessary in most cases, it is considered good practice to set all your pointers to objects to nil on viewDidUnload. Paul Hegarty explains that on CS193P lecture number 8, Controller Lifecycle.
You can watch it here: http://itunes.apple.com/itunes-u/ipad-iphone-application-development/id473757255?mt=2
You can put this, but you can also put [label release], self.label = nil; or just [label release];
It's memory management so that the memory reserved for that object be garbage collected [memory released]. Very important on old iphone 3g, because it has less memory for the user to run programs but minimal in newer iphone 4+/ios 5.x since it uses arc and you can skip that if you use ARC projects.

Do I set properties to nil in dealloc when using ARC?

I am trying to learn Automatic Reference Counting in iOS 5. Now the first part of this question should be easy:
Is it correct that I do NOT need to write explicit
release-property statements in my dealloc when using ARC? In other
words, is it true that the following does NOT need a explicit
dealloc?
#interface MyClass : NSObject
#property (strong, nonatomic) NSObject* myProperty;
#end
#implementation MyClass
#synthesize myProperty;
#end
My next and more important question comes from a line in the Transitioning to ARC Release Notes document:
You do not have to (indeed cannot) release instance variables, but you may need to invoke [self setDelegate:nil] on system classes and other code that isn’t compiled using ARC.
This begs the question: how do I know which system classes are not compiled with ARC? When should I be creating my own dealloc and explicitly setting strongly retaining properties to nil? Should I assume all NS and UI framework classes used in properties require explicit deallocs?
There is a wealth of information on SO and elsewhere on the practices of releasing a property's backing ivar when using manual reference tracking, but relatively little about this when using ARC.
Short answer: no, you do not have to nil out properties in dealloc under ARC.
Long answer: You should never nil out properties in dealloc, even in manual memory management.
In MRR, you should release your ivars. Nilling out properties means calling setters, which may invoke code that it shouldn't touch in dealloc (e.g. if your class, or a subclass, overrides the setter). Similarly it may trigger KVO notifications. Releasing the ivar instead avoids these undesired behaviors.
In ARC, the system automatically releases any ivars for you, so if that's all you're doing you don't even have to implement dealloc. However, if you have any non-object ivars that need special handling (e.g. allocated buffers that you need to free()) you still have to deal with those in dealloc.
Furthermore, if you've set yourself as the delegate of any objects, you should un-set that relationship in dealloc (this is the bit about calling [obj setDelegate:nil]). The note about doing this on classes that aren't compiled with ARC is a nod towards weak properties. If the class explicitly marks its delegate property as weak then you don't have to do this, because the nature of weak properties means it'll get nilled out for you. However if the property is marked assign then you should nil it out in your dealloc, otherwise the class is left with a dangling pointer and will likely crash if it tries to message its delegate. Note that this only applies to non-retained relationships, such as delegates.
Just to give the opposite answer...
Short answer: no, you don't have to nil out auto-synthesized properties in dealloc under ARC. And you don't have to use the setter for those in init.
Long answer: You should nil out custom-synthesized properties in dealloc, even under ARC. And you should use the setter for those in init.
The point is your custom-synthesized properties should be safe and symmetrical regarding nullification.
A possible setter for a timer:
-(void)setTimer:(NSTimer *)timer
{
if (timer == _timer)
return;
[timer retain];
[_timer invalidate];
[_timer release];
_timer = timer;
[_timer fire];
}
A possible setter for a scrollview, tableview, webview, textfield, ...:
-(void)setScrollView:(UIScrollView *)scrollView
{
if (scrollView == _scrollView)
return;
[scrollView retain];
[_scrollView setDelegate:nil];
[_scrollView release];
_scrollView = scrollView;
[_scrollView setDelegate:self];
}
A possible setter for a KVO property:
-(void)setButton:(UIButton *)button
{
if (button == _button)
return;
[button retain];
[_button removeObserver:self forKeyPath:#"tintColor"];
[_button release];
_button = button;
[_button addObserver:self forKeyPath:#"tintColor" options:(NSKeyValueObservingOptions)0 context:NULL];
}
Then you don't have to duplicate any code for dealloc, didReceiveMemoryWarning, viewDidUnload, ... and your property can safely be made public. If you were worried about nil out properties in dealloc, then it might be time you check again your setters.

Deallocating IBOutlets and instance vars

This is something I should have cleared up long ago, but I just need to know the best practice for deallocating in the following scenario.
In my header file I declare a reference to an IBOutlet as follows:
#interface Test : UIViewController {
UIButton *_loginBtn;
}
#property (nonatomic, retain) IBOutlet UIButton *loginBtn;
And in the implementation file I associate the instance variable to the property and deallocate as follows:
#implementation Test
#synthesize loginBtn = _loginBtn;
...
- (void) dealloc {
[_loginBtn release];
self.loginBtn = nil;
[super dealloc];
}
- (void) viewDidUnLoad {
[_loginBtn release];
self.loginBtn = nil;
[super viewDidUnLoad];
}
Am I correct in the deallocating the instance variable and setting the property to nil and doing this in both the viewDidUnLoad and dealloc methods?
There is no need for self.loginBtn = nil; in dealloc, the previous line released it. It is best not to use the property to release it in dealloc. The reason for releasing vs setting the property to nil is that the setter is a method call and the class is in the midst of tearing down and things may be unstable.
In viewDidUnLoad release any properties that are IBOutlets with self.theOutlet = nil;, in this case the _loginBtn release]; is not needed and redundant. Also release any other objects that you can easily re-create.
If properties are used they should be used for all accesses in the class with two exceptions: init and dealloc. In both of these cases the class is partially complete. In these two cases it is best to use the ivar directly in init (if necessary) and release in dealloc.
No, this is incorrect. By first releasing _loginBtn and then setting the property to nil, you release the instance twice. The correct way to do it is to release _loginBtn and then set _loginBtn to nil.

When to release an instance variable

Basically I have this scenario going on:
//in interface header
#property(nonatomic,retain)OtherClass *otherClass;
//implementation
- (id)initWithOtherClassInstance:(OtherClass*)otherClass
{
if (self != [super init])
return self;
self.otherClass = otherClass;
return self;
}
- (void)dealloc
{
//Do I need to release otherClass ?
[otherClass release];
[super dealloc];
}
I'm wondering whether I should release an instance variable on which not explicitly alloc, new or copy was called? The memory management guides say I shoud not, but what I'm worrying about is that self.otherClass = otherClass would retain the instance variable and thus cause a leak when I would decide to not release it in the dealloc method.
Moreover releasing the instance variable in the dealloc method does not generate an exception, which it would in case it was overreleased.
Does my reasoning here make any sense, and what is the best thing to do in a case like this ?
Yes you do need to release this, as other answers suggest. But I find that explicitly calling [foo release] on an ivar that you retained via property setter to be a little unbalanced. I prefer setting self.otherClass = nil; in these scenarios.
Of course under the hood it will do a release for you, but it just looks more balanced and clean.
You are doing this right, the rule you mentioned is the 'create' rule. You still need to match all your retains with releases as well.
Your init method is wrong. You need to assign the result of [super init] to self.
Other than that, assuming that self.otherClass is a retain property, what you have done is sort of OK. If you insist on using the property in -init you should assign the property to nil in dealloc, as Ben says, because then whether the property is assign, retain or copy, the right thing will happen.
However,
it is recommended that you do not use accessors in the -init and -dealloc methods. This is because subclasses may override them to do things you don't expect and KVO observers might get notified in dealloc. So you should probably just set and retain the ivar in init and release it in dealloc.
Note that
self.otherClass = otherClass
is the same as
[self setOtherClass:otherClass]
The default implementation on setOtherClass: looks like
- (void) setOtherClass:(OtherClass*)other
{
[other retain];
[otherClass release];
otherClass = other;
}
As you can see, it retains the object, so you have to release it somewhere.
If you don't like explicit release without explicit alloc, new or copy, then you can do the next in dealloc:
- (void) dealloc
{
[self setOtherClass:nil];
[super dealloc];
}

Should I release this property?

I'm a objective c newbie, and i'm having a bit of problems with memory management, I've read the apple's memory management policies, however i need a bit of clarification here, this is pretty simple i guess, but i would like to ask you if I'm right:
Given this property:
#interface Test : NSObject {
NSArray *property1;
}
#property (nonatomic,retain) NSArray* property1;
#end
...
//And its implementation:
#implementation Test
#synthetize property1;
-(id) init {
if (self=[super init]) {
self.property1=[[[NSArray alloc] initWithCapacity:5] autorelease];
}
return self;
}
-(void) dealloc {
[super dealloc];
[property1 release];
}
#end
Is it right to issue an Autorelease message to the allocated object in the init method?, i do this cause in apple's document, says that every allocated object should be released by the developer, then, I think, alloc sets retain count to 1, then the property (nonatomic, retain) adds 1, so retain==2, then autorelease substracts 1, and when the dealloc method is called, property1 is released and retain count==0, am I right?
You have your memory management right, though Apple (and a lot of other people) generally recommend not using accessors in your initialization methods because accessors can have side effects beyond simply setting an instance variable that your class might not be set up to handle yet. And in that case, you wouldn't want to autorelease since you'd want ownership of the object.
one side note: in your dealloc, you need to release the property before calling [super dealloc], because [super dealloc] eventually deallocates the memory of the object, which includes the memory containing the property1 variable, so it is invalid to refer to that variable after you call [super dealloc]. It should be:
-(void) dealloc {
[property1 release];
[super dealloc];
}
One of the nice things about using properties is that you can encapsulate all of your "releasing" behavior regardless of whether your property is set to retain, copy, assign, or whatever by just doing this:
self.property1 = nil;
Personally I've gotten in the habit of setting all properties to nil (using self.property, not just accessing the member variable directly) in dealloc so that even if I change how the memory management works for the member variable it works correctly.