views:

145

answers:

2
A: 

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.

Jason McCreary
I suggest you review the Cocoa Memory Management Programming Guide. http://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html#//apple_ref/doc/uid/20000994-BAJHFBGH Only if the method name begins with `alloc` or `new` or contains `copy` will you get back a new object.
Robot K
Thanks for the reference and clarification. I will have to recheck those times I ignored instruments and see if I made a similar mistake.
Jason McCreary
+2  A: 

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;
}
Robot K
Robot K beat me to it. To clarify: it's like that when you're calling -roundTo15:, the NSDate instance that you passed to it was still retained by someone when you pulled the rug out from under it (by assigning it to a new date instance). Robot K is correct - create a new NSDate pointer and return that instead of reassigning dateToRound.
Joshua Nozzi
The problem is not `roundTo15:`; there is no problem with it. The problem is its caller, which is passing in a date object that it owns, then replacing that object with `roundTo15:`'s return value without releasing the previous date (and possibly without retaining the new date either). Consider passing the result of `roundTo15:` to a property setter (`self.myDate = …`) instead of assigning directly to the instance variable (`myDate = …`).
Peter Hosey
Could you guys please have a look again, I have updated the question.
Neigaard
Don't call autorelease on roundedDate. It's already an autoreleased object.
Robot K
I've updated the my sample code appropriately.
Robot K