1

How do you get around the cross retain situation when two objects retain each other?

consider this class structure:

Container.h

@interface Container : NSObject {
    NSObject *child;
}

@property (nonatomic, retain) NSObject *child;
@end

Container.m

@implementation Container

@synthesize child;

- (void)dealloc {
    [child release];
    [super dealloc];
}

@end

Then when testing the memory retain count:

- (void)testDoubleRetain {
    Container *A = [[Container alloc] init];
    Container *B = [[Container alloc] init];

    NSLog(@"A retainCount: %d", [A retainCount]);//returns 1
    NSLog(@"B retainCount: %d", [B retainCount]);//returns 1
    [A setChild:B];
    [B setChild:A];

    NSLog(@"A retainCount: %d", [A retainCount]);//returns 2
    NSLog(@"B retainCount: %d", [B retainCount]);//returns 2

    [A release];
    [B release];

    NSLog(@"A retainCount: %d", [A retainCount]);//returns 1
    NSLog(@"B retainCount: %d", [B retainCount]);//returns 1
}

So, from my understanding the retain count supposed to be showing the right count. but how do I end up actually deallocating the objects, since after this block of code those two objects are gonna stay in memory.

JasonMArcher
  • 14,195
  • 22
  • 56
  • 52
Edward Ashak
  • 2,411
  • 2
  • 23
  • 38
  • What does the `setChild` function do? Also, it seems strange that A and B are children of each other. When would this be useful? – Evan Mulawski May 06 '11 at 14:33
  • setChild retains the object you give it. I had this situation with different types of objects that retained each other, but for simplicity reasons my example here uses the same questions. but in real life situation those would be two different class types – Edward Ashak May 09 '11 at 15:15

2 Answers2

2

Simple workaround may be to nil a child before releasing an object itself:

A.child = nil;
[A release];

But to avoid your problem it may be worth rethinking your general program structure so you won't need to have 2 objects mutually retain each other (may be their relationship allow to use 'assign' property instead of 'retain' and you can make sure they won't get deallocated prematurely by other means - e.g. by putting all of them to some global container - that all will depend on your actual context)

Vladimir
  • 170,431
  • 36
  • 387
  • 313
  • this seems to be the solution, if m using assign on an object and that object gets released before me i would end up calling a deallocated object and crash. any thoughts on that situation ? – Edward Ashak May 06 '11 at 14:53
  • 1
    if you use assign property then you need to make sure your object does not get deallocated some other way - may be have 1 external object dedicated to retaining your containers - what exactly you need to do may depend on your context and general architecture of your app – Vladimir May 06 '11 at 15:10
  • Thank you Vlad, this seems to be the option m going to be taking. I'm going to be testing the assign option and make sure that my objects are not released before we m finished with them, then I'll be safely using the assign property. – Edward Ashak May 06 '11 at 18:24
  • I've checked the assign property instead of retain, that seems to be the superior solution. Thanks for your help man – Edward Ashak May 09 '11 at 15:19
1

First, do not use retainCount. It doesn't do what you think.

The normal thing to do here is have either the child or the container not retain the other, which will break the cycle. If that isn't possible, provide a function that must be explicitly called to tell the container that you are done with it, at which point it will release the child.

Community
  • 1
  • 1
Anomie
  • 92,546
  • 13
  • 126
  • 145
  • Yea, i've been reading about the retainCount not being accurate. from what i've seen it is most of the time unless your using UIKit and adding subviews and not removing them at the end of that object's life cycle then you end up with a retained object. – Edward Ashak May 06 '11 at 14:52
  • 1
    @Edward, there are lots of caviets when dealing with retaintCount. In your case, you're calling retainCount after you've released ownership of an object, which is always a bug and will never return zero, so the fact that it returns 1 actually means nothing. A more correct thing to do is add logging to your dealloc method. That way, you'll know concretely whether a object instance has been dealloced or not. – Darren May 06 '11 at 15:10