开发者

If two objects depend on each other with retain property, when the get released finally?

Person.h #import

@interface Person : NSObject {
    NSString *name;
    int age;
    Person *spouse;
}

@property (nonatomic, retain) NSString* name;
@property int age;
@property (nonatomic, retain) Person *spouse;

- (id) initWithName:(NSString *)n age:(int)a;
- (id) initWithName:(NSString *)n age:(int)a spouse:(Person*)s;

@end

Person.m

@implementation Person

@synthesize name;
@synthesize age;
@synthesize spouse;

-(id) initWithName:(NSString *)n age:(int)a
{
    return [self initWithName:n age:a spouse:nil];
}

-(id) initWithName:(NSString *)n age:(int)a spouse:(Person *)s
{
    if((self = [super init]))
    {
        self.name = n;
        self.age = a;
        self.spouse = s;
    }
    return self;
}

-(NSString *)description
{
    return [NSString stringWithFormat:@"name=%@, age=%d, spouse=%@", self.name, self.age, self.spouse.name];
}

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

@end

Then I have code like this

Person *person1 = [[Person alloc] ini开发者_如何学GotWithName:@"Matt" age:33];
Person *person2 = [[Person alloc] initWithName:@"Clair" age:29 spouse:person1];
person1.spouse = person2;
NSLog(@"%@", person1);
NSLog(@"%@", person2);
NSLog(@"person1.retainCount=%d, person2.retainCount=%d", person1.retainCount, person2.retainCount);

[person2 release];
NSLog(@"person1.retainCount=%d, person2.retainCount=%d", person1.retainCount, person2.retainCount);
[person1 release];
NSLog(@"person1.retainCount=%d, person2.retainCount=%d", person1.retainCount, person2.retainCount);

At last, person1.retainCount=1 person2.retainCount=1, they never get -(void) dealloc, so when this situation comes up, how to deal with...


What you have here is called a retain cycle and it is the biggest flaw with a reference counting memory management scheme. This is why the convention that delegates are not retained exists.

You need to find a way to either break the cycle (e.g. before releasing a person, set their spouse to nil, and possibly their spouse's spouse) or avoid it altogether. You could, for instance, create a marriage class with two assign properties, one for each partner, and instead of a spouse property, each person has a retain marriage property pointing to the marriage object. Then when a person is deallocated (and it will be now), you set the marriage property for the other partner to nil.

So your interfaces will look something like this:

@interface Person
 // ...

@property (retain) Marriage* marriage;
@property (readonly, retain) Person* partner;
@end

@interface Marriage

/*
 * DOES NOT RETAIN THE TWO PASSED IN PEOPLE
 */
-(id) initWithPartner: (Person*) aPerson andSpouse: (Person*) anotherPerson; 

/*
 *  Returns the other person in the marriage or nil if the passed in person is not in
 *  this marriage
 */
-(Person*) partnerOf: (Person*) aPerson;
/*
 *  Removes a person from a marriage.
 */
-(void) removePartner: (Person*) aPerson;

@end

Person's dealloc would look something like this.

-(void) dealloc
{
    Person* thePartner = [self partner];

/*
 *  Remove both partners from the marriage so that if something else has retained it, there will not be a problem
 *  with dangling pointers
 */
    [[self marriage] removePartner: thePartner];
    [[self marriage] removePartner: self];
    [[self partner] setMarriage: nil]; // anulls the marriage
    [self setMarriage: nil];           // Assuming only self and our partner owned the marriage, it will now be gone  
    [super dealloc];
}

Person's partner property is implemented thus:

-(Person*) partner
{
    return [[self marriage] partnerOf: self];
}

You could also do it the other way around so that the marriage owns the people and the people have a weak reference to the marriage.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜