views:

228

answers:

3

Hi All, Im just wrapping up my app, so im onto the stage of running instruments to identify leaks in the app. Ive come across a leak that I cannot work out why it is being registered as a leak.

I have the following lines for example:

NSString *imageType = [[[NSString alloc] initWithString:[loopString substringToIndex:[loopString rangeOfString:@"</IMAGE>"].location]] autorelease];
imageType = [imageType substringFromIndex:[imageType rangeOfString:@"<IMAGE>"].location + :@"<IMAGE>".length];

So basically all im doing is pulling out a section of the "loopstring" and putting that into the imagetype string than just cutting off the trailing fluff of the string using the SubstringFromIndex method.

When I run instruments it says "NSCFString substringwithRange" leak. It highlights the second line:

imageType = [imageType substringFromIndex:[imageType rangeOfString:@"<IMAGE>"].location + :@"<IMAGE>".length];

I would think the substringFromIndex method should return a string that is automatically added to the autorelease pool.

Any ideas on where im going wrong?

Thanks

Following is the refactored code:

- (void)SetupTop10:(NSString *)Top10Data
{
while (Top10Data != @"") {
    NSLog(Top10Data);
    if ([Top10Data rangeOfString:@"</TOP10ENTRY>"].location == NSNotFound){
        Top10Data = @"";
    }
    else
    {

        NSString *loopString = [Top10Data substringToIndex:[Top10Data rangeOfString:@"</TOP10ENTRY>"].location + 13];
        Top10Data = [Top10Data stringByReplacingOccurrencesOfString:loopString withString:@""]; 

        //NOW CREATE A RECORD FOR THIS ITEM
        NSString *imageType = [loopString substringToIndex:[loopString rangeOfString:@"</IMAGE>"].location];
        imageType = [imageType substringFromIndex:[imageType rangeOfString:@"<IMAGE>"].location + 7];
        NSString *displayText = [loopString substringToIndex:[loopString rangeOfString:@"</DISPLAYTEXT>"].location];
        displayText = [displayText substringFromIndex:[displayText rangeOfString:@"<DISPLAYTEXT>"].location + 13];
        NSString *link = [loopString substringToIndex:[loopString rangeOfString:@"</INTERESTID>"].location];
        link = [link substringFromIndex:[link rangeOfString:@"<INTERESTID>"].location + 12];
        [Top10Images addObject:imageType];
        [Top10Links addObject:link];
        [Top10s addObject:displayText];
        Top10RowCount = Top10RowCount + 1;
    } 
}

[self.Top10Table reloadData];
Top10Table.hidden = NO;
loadingLabel.hidden = YES;
loadingIndicator.hidden = YES;

}

//********

A: 

It doesn't look leaky. But why

NSString *imageType = [[[NSString alloc] initWithString:
             [loopString substringToIndex:[loopString
                                             rangeOfString:@"</IMAGE>"].location]
         ] autorelease];

if you effectively get the same with

NSString *imageType = [loopString substringToIndex:[loopString
                                             rangeOfString:@"</IMAGE>"].location];

with half the memory usage?

mvds
Sorry this was my first app so there is a still bit of hacky code left.But that doesn't explain the reason why it should be leaking.
Trevor
And also the second line should be: imageType = [imageType substringFromIndex:[imageType rangeOfString:@"<IMAGE>"].location + @"<IMAGE>".length];
Trevor
you must realize that instruments is also just a tool, which can make mistakes. Keeping code clean and tidy helps preventing them. try changing `@"<IMAGE>".length` to `7`. Are you sure there's not other hacky code around these lines?
mvds
Yeah i just refactored the code removing the initwithstring and i also changed the @"<IMAGE>".length to 7 but still the problem persists.
Trevor
Please update your question with the current code, so we all know what we're talking about. Please also tell what happens with imageType after these lines.
mvds
Hi mvds, I posted the updated code in the question. All im doing is looping through a string and putting the entries into MutableArrays.
Trevor
Are the mutablearrays properly released?
mvds
Yeah the arrays are released in the dealloc.
Trevor
Then there is no memory leak, based on the information you give here.
mvds
You've refactored it away, but for the record: @"String".length is not proper Objective-C, since length is *not* defined as a property. It should be [@"String" length]. This is (obviously) not the cause of your leak, but it is a mistake.
Steven Fisher
+1  A: 

Leaks will tell you where the leaked memory was allocated. If you click around (there's a right-arrow icon by the memory address, I think) then you can look at all the allocations/retains/releases for that addresses.

In this example, Leaks will point you to the first line, when it's the fifth one that "leaks" (actually it's a missing release in dealloc/on assignment that leaks):

NSString * s = [someString substringFromIndex:1];
[myArray addObject:s];
// ...
NSString * s2 = [myArray lastObject];
instanceVariable = [s2 retain];
// ... and forget to release in dealloc

What does tableView:cellForRowAtIndexPath: do?

tc.
+1  A: 

I can't see any problem in the above code. Did you release Top10Images in your dealloc method?

joerick
Or possibly it was retained an extra time somewhere. Or perhaps the object was accessed out of Top10Images and retained an extra time somewhere. But the cause of the leak is going to be outside of the code provided.
Steven Fisher