NSImage leaking?
So I'm trying to duplicate the SourceView example in my app. I can generate the source list perfectly, fine. I can also expand the containers, and everything is displayed fine. However, when I select an item in the list, the app crashes with an EXC_BAD_ACCESS.
Backtrace:
SourceListCell
Backtrace:
Code:
#0 0x7fff86532340 in objc_msgSend_vtable14
#1 0x7fff8508f622 in -[NSImage _deallocAuxiliaryStorage]
#2 0x7fff8508f5a1 in -[NSImage dealloc]
*#3 0x100002913 in -[SourceListCell setImage:] at SourceListCell.m:23
*#4 0x100001c31 in -[ProjectController outlineView:willDisplayCell:forTableColumn:item:] at ProjectController.m:166
#5 0x7fff85103085 in -[NSTableView preparedCellAtColumn:row:]
#6 0x7fff8511bc3f in -[NSTableView _drawContentsAtRow:column:withCellFrame:]
#7 0x7fff8511bbb5 in -[NSOutlineView _drawContentsAtRow:column:withCellFrame:]
#8 0x7fff8511acd8 in -[NSTableView drawRow:clipRect:]
#9 0x7fff8511a5cb in -[NSTableView drawRowIndexes:clipRect:]
#10 0x7fff8511a44c in -[NSOutlineView drawRowIndexes:clipRect:]SourceListCell
Code:
@interface SourceListCell : NSTextFieldCell {
NSImage *image;
}
@property(nonatomic, retain) NSImage *image;
@end
- (id)init {
self = [super init];
[self setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
return self;
}
- (void)dealloc {
[image release];
image = nil;
[super dealloc];
}
- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView {
if (image != nil) {
[image setSize:NSMakeSize(kIconImageSize, kIconImageSize)];
// the cell has an image: draw the normal item cell
NSSize imageSize;
NSRect imageFrame;
imageSize = [image size];
NSDivideRect(cellFrame, &imageFrame, &cellFrame, 3 + imageSize.width, NSMinXEdge);
imageFrame.origin.x += kImageOriginXOffset;
imageFrame.origin.y -= kImageOriginYOffset;
imageFrame.size = imageSize;
if ([controlView isFlipped])
imageFrame.origin.y += ceil((cellFrame.size.height + imageFrame.size.height) / 2);
else
imageFrame.origin.y += ceil((cellFrame.size.height - imageFrame.size.height) / 2);
[image compositeToPoint:imageFrame.origin operation:NSCompositeSourceOver];
NSRect newFrame = cellFrame;
newFrame.origin.x += kTextOriginXOffset;
newFrame.origin.y += kTextOriginYOffset;
newFrame.size.height -= kTextHeightAdjust;
[super drawWithFrame:newFrame inView:controlView];
}
}Code:
- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(NSCell*)cell forTableColumn:(NSTableColumn*)tableColumn item:(id)item {
if ([[tableColumn identifier] isEqualToString:COLUMNID_NAME]) {
if ([cell isKindOfClass:[SourceListCell class]]) {
//item = [item representedObject];
NSImage *iconImage;
iconImage = [[NSWorkspace sharedWorkspace] iconForFile:[item path]];
[item setNodeIcon:iconImage];
[(SourceListCell*)cell setImage:[item nodeIcon]];
}
}
}
What's in setNodeIcon: etc?
Nothing, I @synthesize it
@property(nonatomic, retain) NSImage *nodeIcon;
@property(nonatomic, retain) NSImage *nodeIcon;
Ah. Looking again: the crash actually has nothing to do with any of the code you posted. 
Implement copyWithZone:.

Implement copyWithZone:.
Sweet! Thank you
Do you know why it crashed though?
Cells in table/outline views are constantly being copied by Cocoa for various reasons. The NSCell implementation of copyWithZone: copies all instance variable values. This means that a copy of SourceListCell will have a pointer to the same NSImage instance as the SourceListCell instance it was copied from. Both instances (and potentially many more copies) will eventually try to release that NSImage instance in -dealloc, but every copy never retained the image in the first place.
Thus, all NSCell subclasses with retained objects must implement copyWithZone: to explicitly retain or copy them so they don't get over released.
Cells in table/outline views are constantly being copied by Cocoa for various reasons. The NSCell implementation of copyWithZone: copies all instance variable values. This means that a copy of SourceListCell will have a pointer to the same NSImage instance as the SourceListCell instance it was copied from. Both instances (and potentially many more copies) will eventually try to release that NSImage instance in -dealloc, but every copy never retained the image in the first place.
Thus, all NSCell subclasses with retained objects must implement copyWithZone: to explicitly retain or copy them so they don't get over released.
Possibly Related Threads...
| Thread: | Author | Replies: | Views: | Last Post | |
| Sending an NSImage on a Network | mindwalkernine | 1 | 2,759 |
Aug 9, 2006 04:23 AM Last Post: djork |
|
| Animate An NSImage | mindwalkernine | 1 | 3,548 |
Jun 18, 2006 12:30 AM Last Post: StealthyCoin |
|
| NSImage and NSView problems | Joseph Duchesne | 1 | 3,281 |
Aug 19, 2005 07:36 AM Last Post: unknown |
|
| Faking a Z Coordinate With NSImage | Nick | 2 | 2,559 |
Jun 11, 2005 05:38 PM Last Post: Nick |
|
| Drawing: Transparent Pixels and NSImage | elhochme | 4 | 5,054 |
Jun 17, 2003 06:39 PM Last Post: elhochme |
|

