Reputation: 333
another memory management question: I have asked this before, but did not really get an answer:
The question is would the following result in a leak or is it ok?
NSArray *txtArray = [NSArray array];
NSString *aTxtFieldTxt = [[NSString alloc]initWithString:aTxtField.text];
aTxtFieldTxt = [aTxtFieldTxt stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSMutableString *aTxt = [[NSMutableString alloc]initWithString:aTxtFieldTxt];
[aTxtFieldTxt release];
txtArray = [aTxt componentsSeparatedByString:@" "];
aTxt = [[txtArray objectAtIndex:0] retain];
for(int i = 1; i < [txtArray count]; i++){
[aTxt appendString:@"+"];
[aTxt appendString:[[txtArray objectAtIndex:i]retain]];
}
This is part of a function. And I am not sure if the assignment of aTxt = [[txtArray objectAtIndex:0] retain];
causes a leak because it is a pointer which originally points to
NSMutableString *aTxt = [[NSMutableString alloc]initWithString:aTxtFieldTxt];
[aTxtFieldTxt release];
How do I do this correctly. Would I have to use another pointer? Can somebody please explain this issue?
Thanks alot!
Upvotes: 0
Views: 611
Reputation: 1549
Lots and lots of issues with this code.
//
// Don't do this. Just declare the txtArray
//
NSArray *txtArray /* = [NSArray array]*/;
//
// You need to auto release after init in this case.
//
NSString *aTxtFieldTxt = [[[NSString alloc]initWithString:[aTxtField text]] autorelease];
//
// You are reassigning the aTxtFieldTxt and the new value is returned autoreleased.
//
aTxtFieldTxt = [aTxtFieldTxt stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
//
// Again, autorelease after init
//
NSMutableString *aTxt = [[[NSMutableString alloc]initWithString:aTxtFieldTxt] autorelease];
//
// You never alloced this instance so it needs no release.
//
/*[aTxtFieldTxt release]; */
//
// This array is returned autoreleased
//
txtArray = [aTxt componentsSeparatedByString:@" "];
//
// No need to retain here. Just get the object
//
aTxt = /*[*/[txtArray objectAtIndex:0]/* retain]*/;
for(int i = 1; i < [txtArray count]; i++)
{
[aTxt appendString:@"+"];
[aTxt appendString:[[txtArray objectAtIndex:i]retain]];
}
I have found, that if you have retains/releases outside of accessors/base int/dealloc routines, you are doing something wrong. For every alloc you must have a balanced release/retain for that instance of the object. If you reassign the variable, you will loose your reference to it.
This is a quick stab on how I would write this code:
NSArray *txtArray;
NSString *aTxtFieldTxt = [NSString stringWithString:[aTxtField text]];
NSMutableString *aTxt;
aTxtFieldTxt = [aTxtFieldTxt stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
aTxt = [NSMutableString stringWithString:aTxtFieldTxt];
txtArray = [aTxt componentsSeparatedByString:@" "];
aTxt = [NSMutableString stringWithString:[txtArray objectAtIndex:0]];
for(int i = 1; i < [txtArray count]; i++)
{
[aTxt appendString:@"+"];
[aTxt appendString:[[txtArray objectAtIndex:i]retain]];
}
Upvotes: 1
Reputation: 25632
As others pointed out, this code leaks all over the place.
A real good way to find those without even running your code is the static analyzer!
Use Build and Analyze from the Build menu, and it will show you what leaks and why, with complete code paths.
Upvotes: 0
Reputation: 523274
aTxtFieldTxt = [aTxtFieldTxt stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
This will cause the original reference to aTxtFieldTxt
being lost (thus a leak). Even worse, a convenient function will return an object of retain count 0, so the -release
later will crash the program.
It's better written as
// don't stuff everything into a single line.
NSCharacterSet* charsToTrim = [NSCharacterSet whitespaceAndNewlineCharacterSet];
// there's no need to create a copy of the string.
NSString* aTxtFieldTxt = [aTxtField.text stringByTrimmingCharactersInSet:charsToTrim];
// don't release stuff with retain count 0.
// you just want to replace all ' ' by '+' right? there's a method for that.
NSString* aTxt = [aTxtFieldTxt stringByReplacingOccurrencesOfString:@" "
withString:@"+"];
Edit: If you need to replace multiple spaces to one +
, you need to parse the string, e.g.
NSCharacterSet* charsToTrim = [NSCharacterSet whitespaceAndNewlineCharacterSet];
NSString* aTxtFieldTxt = [aTxtField.text stringByTrimmingCharactersInSet:charsToTrim];
NSScanner* scanner = [NSScanner scannerWithString:aTxtFieldTxt];
[scanner setCharactersToBeSkipped:nil];
NSMutableString* aTxt = [NSMutableString string];
NSCharacterSet* whitespaceSet = [NSCharacterSet whitespaceCharacterSet];
while (![scanner isAtEnd]) {
NSString* res;
[scanner scanUpToCharactersFromSet:whitespaceSet intoString:&res];
[aTxt appendString:res];
if ([scanner scanCharactersFromSet:whitespaceSet intoString:NULL])
[aTxt appendString:@"+"];
}
Upvotes: 0
Reputation: 16315
Try running your application with Leaks. See if it causes a leak. Leaks is a tool in Instruments.
Upvotes: 1