Question

I was digging into memory management, i found this.

I created a property button.

@property (nonatomic, retain) UIButton *button;

In ViewdidLoad method, i have written following code.

self.button = [[UIButton alloc] initwithFrame : CGRectMake(10, 10, 20, 20)];
[self.view addsubView:self.button];

Doing XCode analyze, i am getting potential leak of an allocated variable on line 33 i.e; self.button.

Why does this happens? If i create a local UIButton and assign it to self.button and use it, then there is no potential leak. If i alloc memory to self.button or any property variables, it leaks.

Thanks Jithen

Was it helpful?

Solution

Assigning a value to self.button calls the synthesized setter method:

- (void)setButton:(UIButton *)button;

Because you added the "retain" attribute to your property declaration, the synthesized setter will automatically call "retain" on the object that is set. This ups the retain count of the object.

Calling "alloc" on UIButton also ups the object's retain count.

So doing self.button = [UIButton alloc] essentially will up your retain count by 2. That's why there's a potential leak.

You can fix this by doing either:

self.button = [[[UIButton alloc] initwithFrame : CGRectMake(10, 10, 20, 20)] autorelease];

or

UIButton *temp = [[UIButton alloc] initwithFrame : CGRectMake(10, 10, 20, 20)];
self.button = temp;
[temp release];

or

_button = [[UIButton alloc] initwithFrame : CGRectMake(10, 10, 20, 20)]; 

OTHER TIPS

@property (nonatomic, retain) UIButton *button; using this you are retaining object.

Now using self.button = [[UIButton alloc] initwithFrame : CGRectMake(10, 10, 20, 20)]; you are allocating memory and retain count is increased by 1.

So in you case this is a leak as retain count of object is increased. In case if you have local object and you alloc then again releasing it . So there is no extra retain count and there is no leak.

Abstarct

When you use factory method or create object using alloc,new,retain,copy,mutableCopy your object has +1 retain count every time. You own object in this case. You are responsible for releasing it. So you need to release object after you finish using object which cause -1 retain count to object.

EDIT

Now you are doing

@property (nonatomic, assign) UIButton *button;
self.button = [[UIButton alloc] init];
[self.button release];

Here you are accessing object using self which invokes on variable of your created property. You are sending +1 retain count over property object so it becomes 2 as property it self has getter and setters. So instead of doing this you can use instance variable like this.

@property (nonatomic, assign) UIButton *button;
_button = [[UIButton alloc] init];
[_button release];

Before ARC, you would normally do this for a retain variable:

UIButton* btn = [[UIButton alloc] initwithFrame : CGRectMake(10, 10, 20, 20)];
self.button = btn;    // property increases retain count because of its declaration as "retain"
[btn release];

with ARC, you would probably do this:

@property (nonatomic, weak) UIButton* button;

self.button = [[UIButton alloc] initwithFrame : CGRectMake(10, 10, 20, 20)];
[self.view addsubView:self.button];

the second example illustrates that you don't really need to have your property retain the button (via retain or strong) because when you add a subview to a view container, the containing view will retain the new child.

Of course, there are some exceptions. Sometimes, you might actually want to remove your view (button) from the superview, but not let it be released, because you'll add it back later.

So, sometimes, it's valid to retain UI objects. Usually, it's not necessary, though.

Update: I would like to comment here that this kind of problem is why Apple wants people to use ARC. This is a really basic memory management scenario, that continues to foil lots and lots of new developers. At this point, there's very little reason for beginning iOS developers not to be using ARC.

Your UIButton instance is being retained twice. [UIButton alloc] creates a retained instance and the button property is retaining it when assigned via self.button. With MRC (Manual Reference Counting) code you need to release anything you retain.

When you create the button do the following:

UIButton *button = [[[UIButton alloc] initWithFrame:...] autorelease];
self.button = button;

Alternatively, use the preferred creator method for `UIButton':

self.button [UIButton buttonWithType:UIButtonTypeCustom];
self.button.frame = CGRectMake(...);

You also need to release the button wherever you clean up objects assigned to your properties. You're coding will be much simpler if you use ARC (Automatic Reference Counting) instead of MRC.

I don't know whether you have released it or not but whenever we alloc memory, we have to release it(if ARC is not used in your project). So just release it in dealloc like this:

-(void)dealloc {
    [button release];
    [super dealloc];
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top