Objective-C-NSMutableAttributedString 泄漏

发布于 2024-11-28 23:56:20 字数 1644 浏览 0 评论 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];
}

有人可以解释为什么吗?

I am a newbie to Obj-C, and am experimenting with few things.
I stumbled upon one leak issue and would like to know the logical reason behind it.

The following piece of code leaks :

(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];
}

while the following code does not leak :

-(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];
}

Can somebody explain why?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

北座城市 2024-12-05 23:56:20

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

//Remove this line in the first example
[textViewAttrStr retain];

The problem with the first example is the extra retain. You need to remove that because it is already retained when you create the textViewAttrStr with [[NSMutableAttributedString alloc] initWithString:@"Hello "];

//Remove this line in the first example
[textViewAttrStr retain];
绝不放开 2024-12-05 23:56:20

第一个示例:

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

第二个示例

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

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

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

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

First example:

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

Second example

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

You should now see that in your first example, you've alloc/init'd AND retained it, whoops.

Second example, you properly alloc/init'd then released.

Simple rule: If you alloc/init OR copy OR retain, YOU must release at some point. If it is a class variable, release in dealloc, otherwise release before leaving scope.

半世晨晓 2024-12-05 23:56:20

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

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

因此,当您这样做时:

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

对该对象的retain调用与对该对象的release调用相平衡。这几乎什么也没做。删除此处的保留和释放调用可提供相同的功能。一旦你删除这些,你的对象的引用计数为 1,因为你调用了 alloc,并且当 dealloc 命中时,它将达到 0 并被释放。

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

顺便说一句,在向对象发送释放消息之前检查对象是否不为 nil 是不必要的,因为向 nil 发送消息不会执行任何操作。

Your second example shows that you don't understand why you have a leak in the first example, so you have choosen to experiment around, which seems like an understandable approach.

In your second example, textViewAttrStr and tavs are essentially the same. They're both references (or pointers) to the same object in memory.

So, when you do:

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

The call to retain on this object is balanced out with the call to release on this object. This is pretty much doing nothing. Removing the retain and release calls here provides the same functionality. Once you remove those, your object has a reference count of 1 because you called alloc, and when dealloc hits, it will reach 0 and be freed.

Now, in your first example, your object is being alloc'ed (reference count of 1), then retained (reference count of 2), and when dealloc hits, it will reach reference count of 1 and your object will not be freed and thus leak. So the solution here is to remove the call to retain.

By the way, checking if objects are not nil before sending release message to them is unnecessary because sending a message to nil does nothing.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文