Re: Why does this leak memory?
Re: Why does this leak memory?
- Subject: Re: Why does this leak memory?
- From: Matt Ball <email@hidden>
- Date: Mon, 11 Jul 2005 17:04:55 -0400
"image" comes from a dictionary within an array. Each row has a
dictionary assigned to it which stores a variety of information about
it. The image is one of those things. Also, I rewrote the original
shadowedImageWithImage code a long ways back in the chain of messages.
It is currently:
+ (NSImage *)shadowedImageWithImage:(NSImage *)image rowHeight:(int)rowHeight
{
float thumbnailHeight = rowHeight * 0.85;
float thumbnailWidth = (thumbnailHeight / [image size].height) *
[image size].width;
NSSize thumbnailSize = NSMakeSize(thumbnailHeight, thumbnailWidth);
[image setFlipped:YES];
NSImage *resizedImage = [[NSImage alloc] initWithSize:thumbnailSize];
[resizedImage lockFocus];
[NSGraphicsContext saveGraphicsState];
[[NSGraphicsContext currentContext]
setImageInterpolation:NSImageInterpolationHigh];
[image drawInRect:NSMakeRect(0.0, 0.0, thumbnailWidth,
thumbnailHeight) fromRect:NSMakeRect(0.0, 0.0, [image size].width,
[image size].height) operation:NSCompositeCopy fraction:1.0];
[NSGraphicsContext restoreGraphicsState];
[resizedImage unlockFocus];
// [image setFlipped:NO];
int squareSize = 3;
NSImage *imageCanvas = [[NSImage alloc] initWithSize:thumbnailSize];
[imageCanvas lockFocus];
NSRect imageFrame = NSMakeRect(0, 0, [imageCanvas size].width,
[imageCanvas size].height);
NSImage *transparencyPattern = [[NSImage alloc]
initWithSize:NSMakeSize(2*squareSize, 2*squareSize)];
[transparencyPattern lockFocus];
[[NSColor colorWithCalibratedWhite:0.8 alpha:1.0] set];
NSRectFill(NSMakeRect(0,0,squareSize,squareSize));
NSRectFill(NSMakeRect(squareSize,squareSize,squareSize,squareSize));
[[NSColor whiteColor] set];
NSRectFill(NSMakeRect(squareSize,0,squareSize,squareSize));
NSRectFill(NSMakeRect(0,squareSize,squareSize,squareSize));
[transparencyPattern unlockFocus];
[[NSColor colorWithPatternImage:transparencyPattern] set];
NSRectFill(imageFrame);
[resizedImage compositeToPoint:NSMakePoint(0, 0)
operation:NSCompositeSourceOver];
[imageCanvas unlockFocus];
[transparencyPattern release];
thumbnailSize.width += 4;
thumbnailSize.height += 4;
NSImage *shadowCanvas = [[NSImage alloc] initWithSize:thumbnailSize];
[shadowCanvas lockFocus];
NSShadow *theShadow = [[NSShadow alloc] init];
[theShadow setShadowColor:[NSColor blackColor]];
[theShadow setShadowBlurRadius:4];
[theShadow set];
[imageCanvas compositeToPoint:NSMakePoint(2, 1)
operation:NSCompositeSourceOver];
[shadowCanvas unlockFocus];
[theShadow release];
[resizedImage release];
[imageCanvas release];
return [shadowCanvas autorelease];
}
- Matt Ball
On 7/11/05, Ryan Stevens <email@hidden> wrote:
> Okay...
>
> I would try retaining 'image' at the beginning of
> shadowedImageWithImage: and releasing it before returning (since it's
> not clear to me where this image really comes from or who owns it).
> This way it's guaranteed to stick around long enough for you to draw
> it into 'resizedImage'...
>
> + (NSImage *)shadowedImageWithImage:(NSImage *)image
> {
> if (!image) return nil;
>
> [image retain]; // we want this to stick around a bit
> [image setFlipped:YES];
>
>
> // Resize the image, and make sure to antialias it.
> float thumbnailHeight = [tableView rowHeight] * 0.85;
> float thumbnailWidth = (thumbnailHeight / [image
> size].height) *
> [image size].width;
>
>
> NSImage *resizedImage = [[NSImage alloc]
> initWithSize:NSMakeSize(thumbnailHeight, thumbnailWidth)];
>
> [resizedImage lockFocus];
> [NSGraphicsContext saveGraphicsState];
> [[NSGraphicsContext currentContext]
> setImageInterpolation:NSImageInterpolationHigh];
> [image drawInRect:NSMakeRect(0.0, 0.0, thumbnailWidth,
> thumbnailHeight) fromRect:NSMakeRect(0.0, 0.0, [image
> size].width,
> [image size].height) operation:NSCompositeCopy fraction:1.0];
> [NSGraphicsContext restoreGraphicsState];
> [resizedImage unlockFocus];
>
> [image release]; // we don't need this anymore.
>
> return [resizedImage autorelease];
> }
>
>
> On Jul 11, 2005, at 1:39 PM, Matt Ball wrote:
>
> > I'm back to the same crash I was having a long time ago. When I click
> > on a row, it crashes. Here's what I've got (I don't have the retain
> > and release that you had in your willDisplayCell because my "image"
> > variable was declared locally):
> >
> > - (void)tableView:(NSTableView *)tableView willDisplayCell:(id)cell
> > forTableColumn:(NSTableColumn *)tableColumn row:(int)row
> > {
> > NSMutableArray *layersArray = [[[NSDocumentController
> > sharedDocumentController] currentDocument] layersArray];
> > NSMutableDictionary *layerDictionary = [layersArray
> > objectAtIndex:row];
> > if(layersArray != nil) {
> > if([[tableColumn identifier]
> > isEqualToString:@"titleColumn"]) {
> > NSImage *shadowedImage = [NSImage
> > shadowedImageWithImage:[layerDictionary objectForKey:@"Image"]
> > rowHeight:[layersView rowHeight]];
> >
> > if(shadowedImage != nil)
> > [cell setImage:shadowedImage];
> > }
> > }
> > }
> >
> > In my custom cell:
> >
> > - (void)setImage:(NSImage *)anImage
> > {
> > if(anImage != image && anImage != nil)
> > {
> > [image release];
> > image = [anImage retain];
> > }
> > }
> >
> > - (NSImage *)image
> > {
> > return image;
> > }
> >
> > - (void)editWithFrame:(NSRect)aRect inView:(NSView *)controlView
> > editor:(NSText *)textObj delegate:(id)anObject event:(NSEvent
> > *)theEvent
> > {
> > if([self image] != nil) {
> > NSRect textFrame, imageFrame;
> > NSDivideRect (aRect, &imageFrame, &textFrame, 10 + [[self
> > image]
> > size].width, NSMinXEdge);
> > textFrame.origin.y = NSMinY(textFrame) +
> > textFrame.size.height/4 + 2;
> > textFrame.size.height = 18;
> > [super editWithFrame:textFrame inView:controlView
> > editor:textObj
> > delegate:anObject event:theEvent];
> > }
> > else {
> > [super editWithFrame:aRect inView:controlView editor:textObj
> > delegate:anObject event:theEvent];
> > }
> > }
> >
> > - (void)selectWithFrame:(NSRect)aRect inView:(NSView *)controlView
> > editor:(NSText *)textObj delegate:(id)anObject start:(int)selStart
> > length:(int)selLength {
> > if([self image] != nil) {
> > NSRect textFrame, imageFrame;
> > NSDivideRect (aRect, &imageFrame, &textFrame, 10 + [[self
> > image]
> > size].width, NSMinXEdge);
> > textFrame.origin.y = NSMinY(textFrame) +
> > textFrame.size.height/4 + 2;
> > textFrame.size.height = 18;
> > [super selectWithFrame:textFrame inView:controlView
> > editor:textObj
> > delegate:anObject start:selStart length:selLength];
> > }
> > else {
> > [super selectWithFrame:aRect inView:controlView editor:textObj
> > delegate:anObject start:selStart length:selLength];
> > }
> > }
> >
> > - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
> > {
> > // Draw the thumbnail image
> > if (image != nil) {
> > NSSize imageSize;
> > NSRect imageFrame;
> >
> > imageSize = [[self image] size];
> > NSDivideRect(cellFrame, &imageFrame, &cellFrame, 10 +
> > imageSize.width, NSMinXEdge);
> > if ([self drawsBackground]) {
> > [[self backgroundColor] set];
> > NSRectFill(imageFrame);
> > }
> > imageFrame.origin.x += 3;
> > imageFrame.size = imageSize;
> > imageFrame.origin.y = NSMinY(cellFrame) +
> > (cellFrame.size.height -
> > [[self image] size].height)/2;
> >
> > [image drawInRect:imageFrame fromRect:NSMakeRect(0, 0,
> > [[self image]
> > size].width, [[self image] size].height)
> > operation:NSCompositeSourceOver fraction:1.0];
> > }
> > // Modify the cell frame to compensate for the image
> > cellFrame.origin.y = NSMinY(cellFrame) + cellFrame.size.height/
> > 4 + 2;
> >
> > if([self isHighlighted])
> > [self setTextColor:[NSColor
> > alternateSelectedControlTextColor]];
> > else
> > [self setTextColor:[NSColor textColor]];
> > // Draw the cell's text normally
> > [super drawWithFrame:cellFrame inView:controlView];
> > }
> >
> > If I add my copyWithZone back in, I get the editing bug still.
> >
> > - Matt Ball
> >
> > On 7/11/05, Ryan Stevens <email@hidden> wrote:
> >
> >> aha, sorry...
> >>
> >> NSImageCategory.h...
> >>
> >> #import <Cocoa/Cocoa.h>
> >>
> >> @interface NSImage (YourCategoryNameWhichIsNotImportant)
> >> + (NSImage *)shadowedImageWithImage:(NSImage *)image;
> >> @end
> >>
> >>
> >> NSImageCategory.m...
> >>
> >> #import "NSImageCategory.h"
> >>
> >> @implementation NSImage (YourCategoryNameWhichIsNotImportant)
> >> + (NSImage *)shadowedImageWithImage:(NSImage *)image
> >> {
> >> if (!image) return nil;
> >>
> >> [image setFlipped:YES];
> >>
> >>
> >> // Resize the image, and make sure to antialias it.
> >> float thumbnailHeight = [tableView rowHeight] * 0.85;
> >> float thumbnailWidth = (thumbnailHeight / [image
> >> size].height) *
> >> [image size].width;
> >>
> >>
> >> NSImage *resizedImage = [[NSImage alloc]
> >> initWithSize:NSMakeSize(thumbnailHeight, thumbnailWidth)];
> >>
> >> [resizedImage lockFocus];
> >> [NSGraphicsContext saveGraphicsState];
> >> [[NSGraphicsContext currentContext]
> >> setImageInterpolation:NSImageInterpolationHigh];
> >> [image drawInRect:NSMakeRect(0.0, 0.0, thumbnailWidth,
> >> thumbnailHeight) fromRect:NSMakeRect(0.0, 0.0, [image size].width,
> >> [image size].height) operation:NSCompositeCopy fraction:1.0];
> >> [NSGraphicsContext restoreGraphicsState];
> >> [resizedImage unlockFocus];
> >>
> >> return [resizedImage autorelease];
> >> }
> >> @end
> >>
> >>
> >> On Jul 11, 2005, at 1:16 PM, Matt Ball wrote:
> >>
> >>
> >>> I'm afraid I really just don't understand how to use a category.
> >>> Does
> >>> it need to be in a different file? All I did so far was change
> >>> the "-"
> >>> to a "+" in my file. I'm sorry, but I'm very confused.
> >>>
> >>> - Matt Ball
> >>>
> >>> On 7/11/05, Ryan Stevens <email@hidden> wrote:
> >>>
> >>>
> >>>> You should be able to just import the header for the category.
> >>>>
> >>>> On Jul 11, 2005, at 1:07 PM, Matt Ball wrote:
> >>>>
> >>>>
> >>>>
> >>>>> When I do that, I get a warning "NSImage may not respond to
> >>>>> +shadowedImageWithImage" and a crash. I've never used
> >>>>> categories, so
> >>>>> I'm not entirely sure where I have to make changes.
> >>>>>
> >>>>> - Matt Ball
> >>>>>
> >>>>> On 7/11/05, Ryan Stevens <email@hidden> wrote:
> >>>>>
> >>>>>
> >>>>>
> >>>>>> How did our vets miss this? You didn't fix it, you applied a
> >>>>>> fragile
> >>>>>> band-aid where there was no wound.
> >>>>>>
> >>>>>> That method has no business changing what 'image' points to, it
> >>>>>> should use 'image' to create and return a shadowed version.
> >>>>>> That's
> >>>>>> all.
> >>>>>>
> >>>>>> Stick my version of your method in a category and see if your new
> >>>>>> problem doesn't go away.
> >>>>>>
> >>>>>> On Jul 11, 2005, at 11:51 AM, Matt Ball wrote:
> >>>>>>
> >>>>>>
> >>>>>>
> >>>>>>
> >>>>>>> Thanks for the response. I've resolved the memory leak, but now
> >>>>>>> for
> >>>>>>> some reason, my cell acts really weird when I try to edit it.
> >>>>>>> Here is
> >>>>>>> a description of my problem:
> >>>>>>> http://www.cocoabuilder.com/archive/message/cocoa/
> >>>>>>> 2005/7/11/141550
> >>>>>>>
> >>>>>>> - Matt Ball
> >>>>>>>
> >>>>>>> On 7/11/05, Ryan Stevens <email@hidden> wrote:
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>>>
> >>>>>>>> On Jul 10, 2005, at 4:34 PM, Matt Ball wrote:
> >>>>>>>>
> >>>>>>>> I have a function which resizes an image and adds a drop
> >>>>>>>> shadow to
> >>>>>>>> it.
> >>>>>>>> I've determined that it is leaking several NSImage instances.
> >>>>>>>> I've
> >>>>>>>> taken out some code in order to narrow it down, and I've
> >>>>>>>> determined
> >>>>>>>> that this is causing the leak:
> >>>>>>>>
> >>>>>>>> - (NSImage *)shadowedImageWithImage:(NSImage *)image
> >>>>>>>> {
> >>>>>>>> [image setFlipped:YES];
> >>>>>>>>
> >>>>>>>>
> >>>>>>>> // Resize the image, and make sure to antialias it.
> >>>>>>>> float thumbnailHeight = [tableView rowHeight] * 0.85;
> >>>>>>>> float thumbnailWidth = (thumbnailHeight / [image
> >>>>>>>> size].height) *
> >>>>>>>> [image size].width;
> >>>>>>>>
> >>>>>>>>
> >>>>>>>> NSImage *resizedImage = [[NSImage alloc]
> >>>>>>>> initWithSize:NSMakeSize(thumbnailHeight, thumbnailWidth)];
> >>>>>>>> [resizedImage lockFocus];
> >>>>>>>> [NSGraphicsContext saveGraphicsState];
> >>>>>>>> [[NSGraphicsContext currentContext]
> >>>>>>>> setImageInterpolation:NSImageInterpolationHigh];
> >>>>>>>> [image drawInRect:NSMakeRect(0.0, 0.0, thumbnailWidth,
> >>>>>>>> thumbnailHeight) fromRect:NSMakeRect(0.0, 0.0, [image
> >>>>>>>> size].width,
> >>>>>>>> [image size].height) operation:NSCompositeCopy fraction:1.0];
> >>>>>>>> [NSGraphicsContext restoreGraphicsState];
> >>>>>>>> [resizedImage unlockFocus];
> >>>>>>>> image = [resizedImage retain];
> >>>>>>>> [resizedImage release];
> >>>>>>>>
> >>>>>>>> return image;
> >>>>>>>> }
> >>>>>>>>
> >>>>>>>> Could anyone help me figure out why this is leaking? I've read
> >>>>>>>> up on
> >>>>>>>> retain counts, and I think that when I retain "resizedImage," I
> >>>>>>>> increase the retain count such that [resizedImage release];
> >>>>>>>> doesn't
> >>>>>>>> completely release it.
> >>>>>>>>
> >>>>>>>> Any help would be greatly appreciated.
> >>>>>>>>
> >>>>>>>> I would put this in a category and write it like so ...
> >>>>>>>>
> >>>>>>>> + (NSImage *)shadowedImageWithImage:(NSImage *)image
> >>>>>>>> {
> >>>>>>>> if (!image) return nil;
> >>>>>>>>
> >>>>>>>> [image setFlipped:YES];
> >>>>>>>>
> >>>>>>>>
> >>>>>>>> // Resize the image, and make sure to antialias it.
> >>>>>>>> float thumbnailHeight = [tableView rowHeight] * 0.85;
> >>>>>>>> float thumbnailWidth = (thumbnailHeight / [image
> >>>>>>>> size].height) *
> >>>>>>>> [image size].width;
> >>>>>>>>
> >>>>>>>>
> >>>>>>>> NSImage *resizedImage = [[NSImage alloc]
> >>>>>>>> initWithSize:NSMakeSize(thumbnailHeight, thumbnailWidth)];
> >>>>>>>>
> >>>>>>>> [resizedImage lockFocus];
> >>>>>>>> [NSGraphicsContext saveGraphicsState];
> >>>>>>>> [[NSGraphicsContext currentContext]
> >>>>>>>> setImageInterpolation:NSImageInterpolationHigh];
> >>>>>>>> [image drawInRect:NSMakeRect(0.0, 0.0, thumbnailWidth,
> >>>>>>>> thumbnailHeight) fromRect:NSMakeRect(0.0, 0.0, [image
> >>>>>>>> size].width,
> >>>>>>>> [image size].height) operation:NSCompositeCopy fraction:1.0];
> >>>>>>>> [NSGraphicsContext restoreGraphicsState];
> >>>>>>>> [resizedImage unlockFocus];
> >>>>>>>>
> >>>>>>>> return [resizedImage autorelease];
> >>>>>>>> }
> >>>>>>>>
> >>>>>>>>
> >>>>>>>> It seems to me that image = [resizedImage retain]; is your
> >>>>>>>> problem. You
> >>>>>>>> don't want to do that there. Instead...
> >>>>>>>>
> >>>>>>>> - (void)doTheSameThingMinusTheClobber
> >>>>>>>> {
> >>>>>>>> NSImage *shadowed = [NSImage shadowedImageWithImage:image];
> >>>>>>>>
> >>>>>>>> if (!shadowed) return; // NSLog(@"ahh!");
> >>>>>>>>
> >>>>>>>> [image release];
> >>>>>>>> image = [shadowed retain];
> >>>>>>>> }
> >>>>>>>>
> >>>>>>>>
> >>>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>
> >>>>>>
> >>>>>>
> >>>>>>
> >>>>>
> >>>>>
> >>>>>
> >>>>
> >>>>
> >>>>
> >>>
> >>>
> >>
> >>
> >
>
>
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Cocoa-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden