Memory management for Outlets in iOS - objective-c

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.

Related

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.

Object release in Objective-C: Why release an object twice in viewDidUnload and dealloc method?

I have a question about object release in objective-c. I saw some sample codes in Chapter 9 of "Beginning iphone 4 Development"(Page 287). The sample code release an object twice: both in viewDidUnload and dealloc method. Here are the sample codes:
- (void)viewDidUnload {
self.list = nil;
[childController release], childController = nil;}
- (void)dealloc {
[list release];
[childController release];
[super dealloc];}
childController is declared as an instance of UIViewController subclass. Why is it released in both viewDidUnload and dealloc method? Since childController is already released in viewDidUnload, is it necessary to release it again in dealloc method? Based my understanding I will write the code like:
- (void)viewDidUnload {
self.list = nil;
childController = nil;}
- (void)dealloc {
[list release];
[childController release];
[super dealloc];}
Thanks,
Sam
The problem is viewDidUnload is not guaranteed to be called every time like dealloc method. (check this question).
The reason to release objects in viewDidUnload is to avoid memory leaks. Since viewDidUnload is called when there's a low memory warning, you do want to clean up to avoid troubles in that case.
And also calling release on nil will not cause any problem, so it is safe to call release on retained objects in your dealloc method assuming the pointers are set to nil after been released elsewhere (like in viewDidUnload in your example).
In order to optimize available memory, is a good practice to implement lazy getters (actually lazy initializers) in UIViewControllers and release easily reallocable objects in viewDidUnload.
A (simplified) lazy getter is something like:
- (UIView *)footerView {
if (_footerView) {
return _footerView;
}
UIView *view = [[UIView alloc] initWithFrame:A_FRAME];
return (_footerView = view);
}
so, in the viewDidUnload I will release _footerView, because I can retrieve it later without effort. The release of _footerView in dealloc method, is not an error, because:
1) in objective c is ok to send messages to nil objects, 2) dealloc won't be executed at the same time as viewDidUnload but later
I've investigated a little bit because I was not sure. And all you need to know is here: When should I release objects in -(void)viewDidUnload rather than in -dealloc?
Basically, in viewDidUnload you release objects that you've created in the beginning of view's life cycle (loadView, viewDid load and so on). So if your viewController receives memory warning it will unload a view and reload it again and then your objects will be released in viewDidUnload and initialized again in loadView/viewDidLoad/ect

Does dealloc get called after viewDidUnload?

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.

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.