JoJo
JoJo

Reputation: 20115

Why does retain count become 3 after allocating a view and adding it to another view?

Inside the didSelectRowAtIndexPath function of my UITableViewController, I place a UIActivityIndicatorView over the selected UITableViewCell because tapping this cell can potentially issue a slow server request. I printed out the retain count of the UIActivityIndicatorView and noticed that it was 3, when I expected it to be 2.

// @property (nonatomic, retain) UIActivityIndicatorView *spinner;
foo.spinner = [[UIActivityIndicatorView alloc] 
    initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge
];

UITableViewCell *cell = [self.tableView cellForRowAtIndex:indexPath];
[cell addSubView:foo.spinner];

NSLog("retain count of spinner = %d", [foo.spinner retainCount]);

The first retain should happen from foo->setSpinner. The second retain should happen from the tableView adding the spinner as a child view. Where is the 3rd retain? How would you avoid this memory leak?

Upvotes: 1

Views: 446

Answers (4)

nacho4d
nacho4d

Reputation: 45128

You should do:

UIActivityIndicatorView *aSpinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
foo.spinner = aSpinner;
[aSpinner release];

or

foo.spinner = [[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge] autorelease];

Everything else is fine :)

Explanation:

Remember that synthesizing a property like:

@property (nonatomic, retain) UIActivityIndicatorView *spinner;

is basically like:

- (void)setSpinner:(UIActivityIndicatorView *)aSpinner{
    [aSpinner retain];
    [spinner release];
    spinner = aSpinner;
}

So after doing foo.spinner = [[UIActivityIndicatorView alloc] init...]; retain count will be 2 (alloc/init : 1 and 2 since the property is retain). Furthermore, doing [someView addSubview:foo.spinner]; will increase the retain count by 1 so there you have the 3 :)

Upvotes: 2

bbum
bbum

Reputation: 162722

Do Not call retainCount

The absolute retain count of an object is pretty much meaningless and is often very misleading.

Think of the retain count as a delta; you increase it, you decrease it.

So, looking at this code:

// @property (nonatomic, retain) UIActivityIndicatorView *spinner;

// next line is +1 for the property, +1 for the alloc
foo.spinner = [[UIActivityIndicatorView alloc] 
    initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge
];

UITableViewCell *cell = [self.tableView cellForRowAtIndex:indexPath];

// this line may or may not be +1;  doesn't matter. the cell is taking responsibility for
// foo.spinner and whether it retains it or copies it or ignores it is irrelevant
// (obviously, it most likely retains it, but you shouldn't care)
[cell addSubView:foo.spinner];

So, at the end of this, you have two retain count increments that you are responsible for. While you could call release twice in dealloc, that'd be against pattern. So, best to balance the +1 from alloc with a release:

[foo.spinner release];

Upvotes: 1

NSResponder
NSResponder

Reputation: 16861

There is no reason for you to care what the retaincount is. All you should concern yourself with is whether your retains and releases are balanced.

Upvotes: 6

Serhii Mamontov
Serhii Mamontov

Reputation: 4932

Retain count "flow":
1. First retain on alloc
2. Second foo->setSpinner
3. Third addSubview

Upvotes: 1

Related Questions