Objective-C-NSMutableAttributedString 泄漏
我是 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
第一个示例的问题是额外的保留。您需要删除它,因为当您使用
[[NSMutableAttributedString alloc] initWithString:@"Hello "]; 创建
textViewAttrStr
时它已经被保留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 "];
第一个示例:
第二个示例
您现在应该看到,在第一个示例中,您已经分配/初始化并保留了它,哎呀。
第二个例子,你正确地分配/初始化然后释放。
简单的规则:如果你分配/初始化或复制或保留,你必须在某个时刻释放。如果是类变量,则在dealloc中释放,否则在离开作用域之前释放。
First example:
Second example
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.
您的第二个示例表明您不明白为什么第一个示例中存在泄漏,因此您选择进行试验,这似乎是一种可以理解的方法。
在第二个示例中,textViewAttrStr 和 tavs 本质上是相同的。它们都是对内存中同一对象的引用(或指针)。
因此,当您这样做时:
对该对象的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:
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.