简体   繁体   中英

Why does this Objective C code leak memory?

UPDATED

I have this method in Objective C:

-(NSDate*)roundTo15:(NSDate*)dateToRound {
    int intervalInMinute = 15;
    // Create a NSDate object and a NSDateComponets object for us to use
    NSDateComponents *dateComponents = [[NSCalendar currentCalendar] components:NSMinuteCalendarUnit fromDate:dateToRound];

    // Extract the number of minutes and find the remainder when divided the time interval
    NSInteger remainder = [dateComponents minute] % intervalInMinute; 
    // gives us the remainder when divided by interval (for example, 25 would be 0, but 23 would give a remainder of 3

    // Round to the nearest 5 minutes (ignoring seconds)
    if (remainder >= intervalInMinute/2) {
        dateToRound = [dateToRound dateByAddingTimeInterval:((intervalInMinute - remainder) * 60)]; // Add the difference
    } else if (remainder > 0 && remainder < intervalInMinute/2) {
        dateToRound = [dateToRound dateByAddingTimeInterval:(remainder * -60)]; // Subtract the difference
    }

    return dateToRound;
}

This is how I call the method:

item.timestamp = 
    [self roundTo15:[[NSDate date] dateByAddingTimeInterval:60 * 60]];

Instruments says I am leaking a NSDate object when the following line is executed:

dateToRound = [dateToRound dateByAddingTimeInterval:(remainder * -60)];

So it is my item object I need to update with a new corrected NSDate. I tried by making a roundedDate and returning it like this: return [roundedDate autorelease]; , but then I got a bad access error.

The problem is that dateToRound is being passed in as a reference to one object and you are setting it to a reference to a different object. The original object is now abandoned and has been leaked.

You should create a new NSDate * and return it instead of reassigning dateToRound .

Sample code:

-(NSDate*)roundTo15:(NSDate*)dateToRound {
    int intervalInMinute = 15;
    // Create a NSDate object and a NSDateComponets object for us to use
    NSDateComponents *dateComponents = [[NSCalendar currentCalendar] components:NSMinuteCalendarUnit fromDate:dateToRound];

    // Extract the number of minutes and find the remainder when divided the time interval
    NSInteger remainder = [dateComponents minute] % intervalInMinute; // gives us the remainder when divided by interval (for example, 25 would be 0, but 23 would give a remainder of 3

    // Round to the nearest 5 minutes (ignoring seconds)
    NSDate *roundedDate = nil;
    if (remainder >= intervalInMinute/2) {
        roundedDate = [dateToRound dateByAddingTimeInterval:((intervalInMinute - remainder) * 60)]; // Add the difference
    } else if (remainder > 0 && remainder < intervalInMinute/2) {
        roundedDate = [dateToRound dateByAddingTimeInterval:(remainder * -60)]; // Subtract the difference
    } else {
        roundedDate = [[dateToRound copy] autorelease];
    }

    return roundedDate;
}

Some class methods may return a new object on your behalf. Check the documentation, but my guess is that dateByAddingTimeInterval does. That is to say the object returned is not set as autorelease . In which case you would need to release it yourself.

I have found Instruments to report some things that aren't that intuitive. Don't get me wrong, it's a great tool and awesome that you are using. But even some of the sample code from Apple reports leaks.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM