开发者

Objective - C - NSMutableAttributedString Leak

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];
NSMutableAttributedSt开发者_JAVA技巧ring *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?


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


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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜