0

我是 Obj-C 的新手,并且正在尝试一些东西。我偶然发现了一个泄漏问题,并想知道其背后的逻辑原因。

以下代码泄漏

(textViewAttrStr is an instance variable of type NSMutableAttributedString)

-(void) init:(NSString*)str
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

textViewAttrStr = [[NSMutableAttributedString alloc] initWithString:@"Hello "];
NSMutableAttributedString *part1String = [[NSMutableAttributedString alloc] initWithString:str];
[textViewAttrStr appendAttributedString:part1String];
NSMutableAttributedString *part2String = [[NSMutableAttributedString alloc] initWithString:@"!!!"];
[textViewAttrStr appendAttributedString:part2String];
[textViewAttrStr retain];

[part1String release];
[part2String release];

[pool drain];
}

-(void) dealloc
{
if(textViewAttrStr != nil)
{
    [textViewAttrStr release];
}

[super dealloc];
}

而以下代码不会泄漏

-(void) init:(NSString*)str
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

NSMutableAttributedString* tvas = [[NSMutableAttributedString alloc] initWithString:@"Hello "];
NSMutableAttributedString *part1String = [[NSMutableAttributedString alloc] initWithString:str];
[tvas appendAttributedString:part1String];
NSMutableAttributedString *part2String = [[NSMutableAttributedString alloc] initWithString:@"!!!"];
[tvas appendAttributedString:part2String];

textViewAttrStr = tvas;
[textViewAttrStr retain];

[part1String release];
[part2String release];
[tvas release];

[pool drain];
}

-(void) dealloc
{
if(textViewAttrStr != nil)
{
    [textViewAttrStr release];
}

[super dealloc];
}

有人可以解释为什么吗?

4

3 回答 3

2

第一个示例的问题是额外的保留。您需要删除它,因为它在您创建textViewAttrStrwith时已被保留[[NSMutableAttributedString alloc] initWithString:@"Hello "];

//Remove this line in the first example
[textViewAttrStr retain];
于 2011-08-11T14:25:54.153 回答
1

第一个例子:

textViewAttrStr = [[NSMutableAttributedString alloc] initWithString:@"Hello "]; 
//...
[textViewAttrStr retain];

第二个例子

NSMutableAttributedString* tvas = [[NSMutableAttributedString alloc] initWithString:@"Hello "];
//...
[tvas release];

您现在应该看到,在您的第一个示例中,您已经分配/初始化并保留了它,哎呀。

第二个例子,你正确地分配/初始化然后释放。

简单的规则:如果你分配/初始化或复制或保留,你必须在某个时候释放。如果是类变量,则在dealloc中释放,否则在离开作用域前释放。

于 2011-08-11T14:25:35.343 回答
0

您的第二个示例表明您不明白为什么在第一个示例中存在泄漏,因此您选择进行试验,这似乎是一种可以理解的方法。

在您的第二个示例中, textViewAttrStr 和 tavs 基本相同。它们都是内存中同一个对象的引用(或指针)。

所以,当你这样做时:

textViewAttrStr = tvas;
[textViewAttrStr retain];
//...
[tvas release];

对该对象的保留调用与对该对象的释放调用相平衡。这几乎是无所作为。在此处删除保留和释放调用提供了相同的功能。删除这些后,您的对象的引用计数为 1,因为您调用了 alloc,并且当 dealloc 命中时,它将达到 0 并被释放。

现在,在您的第一个示例中,您的对象被分配(引用计数为 1),然后被保留(引用计数为 2),当 dealloc 命中时,它将达到引用计数 1,并且您的对象将不会被释放并且因此泄漏。所以这里的解决方案是去掉retain的调用。

顺便说一句,在向对象发送释放消息之前检查对象是否为 nil 是不必要的,因为向 nil 发送消息什么都不做。

于 2011-08-12T03:22:43.557 回答