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.
精彩评论