views:

141

answers:

4

I have the following instance method (adapted from Listing 3-6 of the Event Handling section in the iPhone Application Programming Guide):

- (CGPoint)originOfTouch:(UITouch *)touch
{
    CGPoint *touchOriginPoint = (CGPoint *)CFDictionaryGetValue(touchOriginPoints, touch);
    if (touchOriginPoint == NULL)
    {
        touchOriginPoint = (CGPoint *)malloc(sizeof(CGPoint)); // leaks
        CFDictionarySetValue(touchOriginPoints, touch, touchOriginPoint);
        *touchOriginPoint = [touch locationInView:touch.view];
    }
    return *touchOriginPoint;
}

Every once in a while my app leaks 16 Bytes as a result of the call to malloc(). I'm not sure how to return touchOriginPoint while free()ing it as well.

+1  A: 

If you must return the malloc'd value from the function, then you have passed the responsibility for freeing the memory to the calling function, or one of its callers.

Since we can't see the calling functions, we can't diagnose any more.

Jonathan Leffler
A: 

If you are going to be returning an object that is allocated, then either you need to have the caller free() it, or else you need to be using some kind of garbage collection (so it gets freed automatically).

vy32
2 seconds behind my answer... :D
Jonathan Leffler
There's no GC in iPhoneOS.
KennyTM
It's very sad that there is no GC in iPhoneOS. I realize that this is an iPhone specific comment, but my answer is a general-purpose one.
vy32
+3  A: 

If you do not care a minor performance loss, use an NSMutableDictionary and store the point as an NSValue:

NSValue* touchOriginPointValue = [touchOriginPoints objectForKey:touch];
if (touchOriginPointValue == nil) {
   touchOriginPointValue = [NSValue valueWithCGPoint:[touch locationInView:touch.view]];
   [touchOriginPoints setObject:touchOriginPointValue forKey:touch];
}
return [touchOriginPointValue CGPointValue];

If you must use the CFDictionary approach, you have to find a place to free those malloc-ed memory when the values are not needed. Therefore, you have to pass the values callbacks when creating the dictionary

static void free_malloced_memory (CFAllocatorRef allocator, const void *value) {
   free((void*)value);
}
static const CFDictionaryValueCallBacks values_callbacks = {0, NULL, free_malloced_memory, NULL, NULL};
...
touchOriginPoints = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, & values_callbacks);
...
KennyTM
Thanks KennyTM, I'll give those callback functions a shot.
Shaun Inman
CFDictionary is required because UITouch doesn't implement NSCopying. While implementing the callback function helps it doesn't eliminate all the related memory leaks.
Shaun Inman
KennyTM
A: 

you don't actually return a pointer, the value is copied to a temp value when it is returned, so you aren't really returning the allocation at all, the problem is that you just aren't freeing it either, you add the allocation to the dictionary and just leave it there?

is there like an EndOfTouch function? where you remove the touch from the dictionary? if there is, call free on your allocation there and you should be fine

matt
There is a touchesEnded method where I free these allocations but I'm finding that when the touch delegate is removed mid-touch that method is never fired resulting in the orphaned allocations.
Shaun Inman
hmm, how is the touch delegate removed? (i'm not too familiar with iphone or objC for that matter). could you go through your list and free everything then?aside from that, could you have a dictionary of actual objects, rather than a dictionary of pointers?, (i don't know how the CFDictionaryGetValue would return if it couldn't find the answer...)that way there would be no allocations to free.
matt