如果两个对象依赖于retain属性,那么get最终会被释放?

时间:2011-05-04 15:37:23

标签: iphone objective-c cocoa-touch

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

然后我有这样的代码

Person *person1 = [[Person alloc] initWithName:@"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);

最后,person1.retainCount = 1 person2.retainCount = 1,他们永远不会得到 - (无效)dealloc,所以当这种情况出现时,如何应对......

1 个答案:

答案 0 :(得分:5)

你在这里称之为保留周期,它是引用计数内存管理方案的最大缺陷。这就是为什么不保留代表的约定。

你需要找到一种方法来打破这个循环(例如在释放一个人之前,将他们的配偶设置为零,可能是他们的配偶的配偶)或完全避免它。例如,您可以创建一个具有两个assign属性的婚姻类,每个伙伴一个,而不是配偶属性,每个人都有一个指向婚姻对象的retain婚姻属性。然后,当一个人被解除分配(现在将是)时,您将另一个伙伴的婚姻属性设置为nil。

所以你的界面看起来像这样:

@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

人的dealloc看起来像这样。

-(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*) partner
{
    return [[self marriage] partnerOf: self];
}

你也可以反过来这样做,以便婚姻拥有人民,而人民对婚姻的参照不足。