Deallocating IBOutlets and instance vars - objective-c

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.

Related

Will ARC be smart enough to release subviews defined in Superclasses too?

I have a custom view class which is a subclass of UITableViewCell.
I have two other custom view classes which inherit from this subclass (they share a lot of the same properties but were different enough to warrant separate classes).
I've declared the shared properties in MyParentCell and also declared their unique properties in the respective classes.
UITableViewCell
|
|
MyParentCell // defines propertyA and propertyB, both IBOutlet subviews
/ \
/ \
/ \
| |
| ChildClass1 // defines propertyC, an IBOutlet subview
|
ChildClass2 // defines property D, an IBOutlet subview
My question is: Since I'm using ARC and cannot explicitly call [super delloc]; when I'm defining dealloc: in ChildClass1 and ChildClass2 do, I have to release all of the subviews they own in each class, or will MyParentCell#dealloc still be called too?
i.e.,
Do I have to write this:
// ChildClass1.m
#implementation ChildClass1
-(void)dealloc
{
self.propertyA = nil;
self.propertyB = nil;
self.propertyC = nil;
}
#end
// ChildClass2.m
#implementation ChildClass2
-(void)dealloc
{
self.propertyA = nil;
self.propertyB = nil;
self.propertyD = nil;
}
#end
Or is it enough to write:
// MyParentCell
#implementation MyParentCell
-(void)dealloc
{
self.propertyA = nil;
self.propertyB = nil;
}
#end
// ChildCell1.m
#implementation ChildCell1
-(void)dealloc
{
self.propertyC = nil;
}
#end
// ChildCell2.m
#implementation ChildCell2
-(void)dealloc
{
self.propertyD = nil;
}
#end
If the second approach is fine, can someone explain when and how MyParentCell#dealloc is called?
If the first approach is necessary, that sucks :/
Of course, also with ARC every class is responsible to clean up only its own resources. If you define a dealloc in a subclass, it's calling the parent's dealloc implicitly at the end of your method. You just don't have to type it.
If you just release instance variables or properties, you can rely on ARC to do this for you after the whole dealloc chain is done. ARC silently implements .cxx_destruct which gets called from NSObject's dealloc and takes care of releasing anything strong in your class.
No not need to use dealloc at all as a general rule(but in some cases), put ain dealloc an NSLog that shows just a dealloc word. Run and trust in ARC everything happen automatically
You don't have to do neither approach 1 nor approach 2. You don't need to implement dealloc at all. When an instance of your subclasses is deallocated, objects it retains will be released automatically. So if they are not retained somewhere else, they will be deallocated too.

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.

Is releasing memory of Objective-c 2.0 properties required?

Something I have been wondering about properties for a while. When you are using properties, do you need to override the release message to ensure the properties are released properties?
i.e. is the following (fictitious) example sufficient?
#interface MyList : NSObject {
NSString* operation;
NSString* link;
}
#property (retain) NSString* operation;
#property (retain) NSString* link;
#end
#implementation MyList
#synthesize operation,link;
#end
You should always release the backing variables in dealloc:
- (void) dealloc {
[operation release];
[link release];
[super dealloc];
}
Another way:
- (void) dealloc {
self.operation = nil;
self.link = nil;
[super dealloc];
}
That's not the preferred way of releasing the objects, but in case you're using synthesized backing variables, it's the only way to do it.
NOTE: to make it clear why this works, let's look at the synthesized implementation of the setter for link property, and what happens when it is set to nil:
- (void) setLink:(MyClass *) value {
[value retain]; // calls [nil retain], which does nothing
[link release]; // releases the backing variable (ivar)
link = value; // sets the backing variable (ivar) to nil
}
So the net effect is that it will release the ivar.
In non-GC applications, yes. It is usual to assign nil instead of releasing the ivars.
My best experience is to release ivars initialized with init and assign nil to properties with retain and copy mode.
In your case I would assign nil
- (void) dealloc {
self.operation = nil;
self.link = nil;
[super dealloc];
}
The best way to do this is:
- (void)dealloc {
[operation release], operation = nil;
[link release], link = nil;
[super dealloc];
}
It would indeed be more convenient to use the generated setter methods
self.operation = nil;
but that is frowned upon. You don't always know which thread an object is deallocated on. Thus using an accessor may cause problems by triggering KVO notifications.
The catch here is that you need to adapt your dealloc to match the object management policy defined in your #property. E.g. don't go releasing a iVar backing an (assign) property.
No, you override the -dealloc method. And yes, if you don't release your properties (or rather, the backing ivars), you will leak. So in your #implementation here you should have something like
- (void)dealloc {
[operation release];
[link release];
[super dealloc];
}
Synthesizing a property only creates getter and setter methods, and therefor won't release the ivar when the object is deallocated. You need to release the ivar yourself.
In pre-ARC whenever you see new, alloc, retain and copy, whether it is an instance var or a property you must release. In ARC whenever you have a strong variable you must set it to nil.
In either case you have to override 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.

Should you set the delegate to nil in the class using the delegate or in the class itself

If class A is using class B and class A is class B's delegate, is it ok if the delegate is set to nil in class B's dealloc? I have seen code usually resetting the delegate to nil inside class A's dealloc but wasn't sure the real difference doing it one way or the other.
e.g. This is the usual way:
// somewhere in class A
- (void) someFunc {
self.b = [[B alloc] init];
self.b.delegate = self;
}
- (void) dealloc {
self.b.delegate = nil;
[self.b release];
}
Yes, you should set the classB's delegate property to nil in classA's dealloc.
It's not a memory management issue, because delegate properties should be marked assign, not retain, to avoid retain cycles (otherwise the dealloc will never be called). The issue is that otherwise classB might message classA after it has been released.
For example, if classB has a delagate call to say "being hidden", and classB is released just after classA, it would message the already dealloc'ed classA causing a crash.
And remember, you can't always guarentee the dealloc order, especial if they are autoreleased.
So yes, nil out the delegate property in classA's dealloc.
As far as I know, its best practice to (assign) a delegate, such that you avoid circular references on retain counts for situations just like this. If you've set up the property properly, ie:
#property (assign) id<BDelegate> delegate;
You shouldn't have to perform any memory management in the dealloc, as the retain count is not bumped when you call self.b.delegate = self; -- unlike using (retain) or (copy)
Make sense? It would be fine to set the delegate to nil, but whats the point?
First, a few observations...
You've forgotten to call [super dealloc] at the end of your own dealloc method.
Since 'a' created 'b', and if no other objects have retained 'b', there no point in nilling the delegate in the -dealloc, since 'b' is about to be destroyed anyhow. If it's possible that other objects have a reference to 'b' (meaning it might outlive 'a') then set the delegate to nil.
Object 'b' should be the one to take care of its delegate in its own -dealloc if necessary. (Generally, the delegator does not retain the delegate.)
Avoid using properties in -init... and -dealloc methods — Apple discourages this, and for good reason. (Not only could it have unexpected side effects, but can also cause nastier, crashier problems.)
Using properties (via the dot syntax) when you don't need to invisibly adds extra work. For instance, self.b.delegate = self is equivalent to [[self getB] setDelegate:self] — it's just syntactic sugar that makes it look like you're accessing the ivar directly, but you're actually not.
Using properties without understanding what they do can lead to trouble. If self.b retains the value (the property is set to "assign"), you have a memory leak on your hands.
Here's how I would probably write it:
- (void) someFunc {
b = [[B alloc] init];
b.delegate = self; // or [b setDelegate:self];
}
- (void) dealloc {
b.delegate = nil;
[b release];
[super dealloc];
}