Reputation: 1027
Suppose I have a view controller like this:
@interface ControllerA : viewcontroller{
NSString * __strong a;
}
@end
and in viewDidLoad
function I set
a = [[NSSString alloc] init];
And in another ControllerB,
{
ControllerA * controllerA = [[ControllerA alloc] init];
}
Will controllerA's member be released?
Upvotes: 5
Views: 6686
Reputation: 2334
There is a well known bug in iOS 5 when using ARC and Zombies enabled that can prevent ivars from being released: Technical Q&A QA1758.
Otherwise, the ivars will be automatically released.
Upvotes: 2
Reputation: 438467
Update 2:
After spending, quite literally, several hours diagnosing and documenting the failure of ivars to be released in my iOS 5 project this morning, I discovered that instance variables are not released in ARC projects if zombies are turned on and run on iOS 5. About to update my answer with these remarkable findings, quite independently, Calin pointed out to me that this is well known behavior. Technical Q&A QA1758. Thanks Calin!
My sample project is at https://github.com/robertmryan/arc-problem-project
Update:
I had previously claimed that this was incorrect and that vars and properties would not be deallocated unless you set them to nil
. I provided the below code as an example. This is taken from a real ARC test project and I even recreated it with another view controller with absolutely nothing in it except the code below to confirm. After a well-deserved chorus of dissents, I put this code sample in a new project, and the ivar was deallocated, as it should be.
So it must be something about the project in question. I've since taken absolutely everything out of that project except the below code (and the view controller that performs the push segue, so that I can pop back to it to demonstrate the deallocation), and the problem persists. If I copy the code (and storyboard) to a new project, it works fine. Very, very strange and I will dig into this more. If you want to see my project, it's at https://github.com/robertmryan/arc-problem-project. Maybe someone else can see what the problem is. I know I can just discard this project (it wasn't even a production app, just a testing platform), but it's worrying that ARC's dealloc can just magically not work properly.
Anyway, to be clear, your ivars are released as the parent object is released. I don't know why my is not releasing in the case below, but that's immaterial to the original question.
// ArcTestViewController.m
#import "ArcTestViewController.h"
#pragma mark - IvarObject
@interface IvarObject : NSObject
@end
@implementation IvarObject
- (void)dealloc
{
NSLog(@"%s", __FUNCTION__);
}
@end
#pragma mark - ArcTestViewController
@interface ArcTestViewController ()
{
IvarObject __strong *_ivarObject;
}
@end
@implementation ArcTestViewController
- (void)dealloc
{
NSLog(@"%s", __FUNCTION__);
// _ivarObject = nil;
}
- (void)viewDidLoad
{
[super viewDidLoad];
_ivarObject = [[IvarObject alloc] init];
}
@end
When I do this with the =nil
statement in the dealloc
method commented out, I see the following on my console:
2012-07-12 10:33:33.644 test4[36045:11903] -[ArcSimpleTestViewController dealloc]
When I uncomment that =nil
statement in my dealloc
, I see the following:
2012-07-12 10:35:23.117 test4[36083:11903] -[ArcSimpleTestViewController dealloc]
2012-07-12 10:35:23.119 test4[36083:11903] -[IvarObject2 dealloc]
To my retraction above, when I put this same code in a new project, I see the deallocs whether I nil or not.
Rob Napier provided the code sample below (I appreciate him and others taking the time), but even the above code works fine when I put it in another project, but in my current project, it doesn't deallocate properly!
Update from Rob Napier: Simpler example (all in one file) that demonstrates how this works. Put this in a file and compile as indicated:
// arc.m
// Compile with:
// clang -fobjc-arc -framework Foundation -o arc arc.m
#import <Foundation/Foundation.h>
#pragma mark - IvarObject
@interface IvarObject : NSObject
@end
@implementation IvarObject
- (void)dealloc
{
NSLog(@"%s", __FUNCTION__);
}
@end
#pragma mark - PropertyObject
@interface PropertyObject : NSObject
@end
@implementation PropertyObject
- (void)dealloc
{
NSLog(@"%s", __FUNCTION__);
}
@end
#pragma mark - ArcTest
@interface ArcTest : NSObject
{
IvarObject __strong *_ivarObject;
}
@property (nonatomic, strong) PropertyObject *propertyObject;
@end
@implementation ArcTest
@synthesize propertyObject = _propertyObject;
- (void)dealloc
{
NSLog(@"%s", __FUNCTION__);
// _ivarObject = nil;
// _propertyObject = nil;
}
- (void)assignStuff
{
_ivarObject = [[IvarObject alloc] init];
self.propertyObject = [[PropertyObject alloc] init];
}
@end
int main () {
ArcTest *test = [[ArcTest alloc] init];
[test assignStuff];
test = nil;
NSLog(@"End program");
}
Upvotes: 1
Reputation: 125037
Yes, the string pointed to by a
will be released when controllerA
is deallocated. You don't need to set it to nil
yourself.
Transitioning to ARC Release Notes is currently the place to look for more information about working with ARC. One important point that it makes is that you may still need a custom -dealloc
if your class needs to do anything other than releasing instance variables when it's instances are deallocated.
Upvotes: 5
Reputation: 33423
You never need to set a variable to nil in ARC unless you want to ensure its deallocation as soon as possible (i.e. [myObject release] under non-ARC code). All iVars will be automatically released when the object is deallocated.
Upvotes: 4