Re: Problem with Outline View and Manual Memory Management
Re: Problem with Outline View and Manual Memory Management
- Subject: Re: Problem with Outline View and Manual Memory Management
- From: Dave <email@hidden>
- Date: Wed, 27 May 2015 13:22:49 +0100
Hi,
Thanks for this, I actually spotted that late last night and I refactored the code to read as below, but it still crashes if I do not retain the "iconImage":
- (void)outlineView:(NSOutlineView *)olv willDisplayCell:(NSCell*)cell forTableColumn:(NSTableColumn *)tableColumn item:(id) item
{
NSImage* iconImage;
NSString* urlStr;
ImageAndTextCell* myCell;
ChildNode* myChildNode;
if ([[tableColumn identifier] isEqualToString:COLUMNID_NAME] == NO)
return;
if ([cell isKindOfClass:[ImageAndTextCell class]] == NO)
return;
iconImage = nil;
myChildNode = [item representedObject];
if (myChildNode == nil)
return;
if ([myChildNode class] != [ChildNode class])
return;
if (myChildNode.isLeaf == YES)
{
urlStr = myChildNode.urlString;
if (urlStr != nil)
{
if ([myChildNode.urlString hasPrefix:HTTP_PREFIX])
{
myChildNode.nodeIcon = self.pURLImage;
}
else
{
iconImage = [[[NSWorkspace sharedWorkspace] iconForFile:urlStr] copy]; //Crashes without retain
LogIfDave(@"Before Get File iconImage - retainCount: %ld",[iconImage retainCount]);
myChildNode.nodeIcon = iconImage;
//******* [iconImage release]; //** Crashes if Present
LogIfDave(@"After set Item iconImage - retainCount: %ld",[iconImage retainCount]);
}
}
}
//**
//** Check if it's a special folder (PLACES or BOOKMARKS), we don't want it to have an icon
//**
else
{
if ([self isSpecialGroup:myChildNode])
{
myChildNode.nodeIcon = nil;
}
else
{
myChildNode.nodeIcon = self.pFolderImage;
}
}
[myChildNode.nodeIcon setSize:NSMakeSize(kIconImageSize,kIconImageSize)];
myCell = (ImageAndTextCell*) cell;
iconImage = myChildNode.nodeIcon;
if (iconImage != nil)
LogIfDave(@"Before set pTextCellImage - retainCount: %ld",[iconImage retainCount]);
myCell.pTextCellImage = iconImage; // Crashes here if release above is present
if (iconImage != nil)
LogIfDave(@"After set Item pTextCellImage - retainCount: %ld",[iconImage retainCount]);
}
—————————————————————————————————————————
This is the Original from SourceView, the problem you spotted is in this code too, in that if item == nil, the code at the end will operate on a nil Object (item).
- (void)outlineView:(NSOutlineView *)olv willDisplayCell:(NSCell*)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
if ([[tableColumn identifier] isEqualToString:COLUMNID_NAME])
{
// we are displaying the single and only column
if ([cell isKindOfClass:[ImageAndTextCell class]])
{
item = [item representedObject];
if (item != nil)
{
if ([item isLeaf])
{
// does it have a URL string?
NSString *urlStr = [item urlString];
if (urlStr)
{
if ([item isLeaf])
{
NSImage *iconImage;
if ([[item urlString] hasPrefix:HTTP_PREFIX])
{
iconImage = urlImage;
}
else
{
iconImage = [[NSWorkspace sharedWorkspace] iconForFile:urlStr];
}
NSLog(@"outlineView: willDisplayCell: forTableColumn: item:");
NSLog(@"URL: %@",[item urlString]);
[item setNodeIcon:iconImage];
}
else
{
NSImage* iconImage = [[NSWorkspace sharedWorkspace] iconForFile:urlStr];
[item setNodeIcon:iconImage];
}
}
else
{
// it's a separator, don't bother with the icon
}
}
else
{
// check if it's a special folder (PLACES or BOOKMARKS), we don't want it to have an icon
if ([self isSpecialGroup:item])
{
[item setNodeIcon:nil];
}
else
{
// it's a folder, use the folderImage as its icon
[item setNodeIcon:folderImage];
}
}
}
// set the cell's image
[[item nodeIcon] setSize:NSMakeSize(kIconImageSize, kIconImageSize)];
ImageAndTextCell *myCell = (ImageAndTextCell *)cell;
myCell.myImage = [item nodeIcon];
}
}
}
All the Best
Dave
> On 27 May 2015, at 12:52, Mark Wright <email@hidden> wrote:
>
> If you paste this in instead does it still crash?:
> Apologies for changing the formatting and structure, I needed to change it up to something I’m used to to read it better.
>
> There’s a problem with the main ‘else’ branch which would only execute if ‘myChildNode’ is nil.
>
> This is how I’d have structured the variables and such so if it manages to compile and doesn’t crash then I can only guess that there was some problem with the re-using or back-assigning of the ‘iconImage’ variable in the bottom few lines.
>
>
>
> - (void)outlineView:(NSOutlineView *)olv willDisplayCell:(NSCell*)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item {
>
> if (![[tableColumn identifier] isEqualToString:COLUMNID_NAME])
> return;
>
> // we are displaying the single and only column
> if (![cell isKindOfClass:[ImageAndTextCell class]])
> return;
>
> ChildNode *myChildNode = [item representedObject];
> if (myChildNode) {
> if (myChildNode.isLeaf == YES) {
>
> NSString *urlStr = myChildNode.urlString;
> if (urlStr) {
> if ([myChildNode.urlString hasPrefix:HTTP_PREFIX]) {
> myChildNode.nodeIcon = self.pURLImage;
> } else {
> NSImage *iconImage = [[NSWorkspace sharedWorkspace] iconForFile:urlStr];
> myChildNode.nodeIcon = iconImage;
> }
> }
> }
> } else {
> //***********************************************************************
> //***** INVALID: myChildNode is nil here from the conditional above *****
> //***********************************************************************
> //**
> //** Check if it's a special folder (PLACES or BOOKMARKS), we don't want it to have an icon
> //**
> if ([self isSpecialGroup:myChildNode]) {
> myChildNode.nodeIcon = nil;
> } else {
> myChildNode.nodeIcon = self.pFolderImage;
> }
> }
>
> // set the cell's image
> [myChildNode.nodeIcon setSize:NSMakeSize(kIconImageSize, kIconImageSize)];
>
> (ImageAndTextCell*)cell.pTextCellImage = myChildNode.nodeIcon;
> }
>
>
>
>
>
>> On 27 May 2015, at 11:48, Dave <email@hidden> wrote:
>>
>> Hi,
>>
>> Sorry, I wasn’t very clear, the VC is my existing VC with the Source Vice Code from “myViewController” code added so this had to be converted to use manual memory management. I also converted the other supporting classes although as you point out, I could have just set the compiler flag.
>>
>> Here are the property definitions from ChildNode:
>>
>> // BaseNide.h
>>
>> @interface BaseNode : NSObject <NSCoding, NSCopying>
>> {
>> }
>>
>> @property (nonatomic,retain) NSString* nodeTitle;
>> @property (nonatomic,retain) NSImage* nodeIcon;
>> @property (nonatomic,retain) NSMutableArray* children;
>> @property (nonatomic,retain) NSString* urlString;
>> @property (nonatomic,assign) BOOL isLeaf;
>>
>>
>> // ChildNide.h
>>
>> @interface ChildNode : BaseNode
>>
>> ———————
>>
>> Here are the property definitions from ImageAndTextCell:
>>
>> @property (nonatomic,retain) NSImage* pTextCellImage;
>>
>> These two are in the View Controller Itself:
>>
>> @property (nonatomic,retain) NSImage* pFolderImage;
>> @property (nonatomic,retain) NSImage* pURLImage;
>>
>> Thanks for your help, I’ve worked on loads of Projects where I’ve had to convert to/from ARC, but never had a problem like this. I’ve obviously missed something, but I’ve been all over the code and it all looks fine. I am worried that the Analyser isn’t showing a problem though, I’ve come to rely on it quite a bit and the fact that I’ve seem it get it wrong a couple of times makes me wonder…..
>>
>> All the Best
>> Dave
>>
>>> On 26 May 2015, at 19:34, Dave <email@hidden> wrote:
>>>
>>> Hi,
>>>
>>> I’ve incorporated the Tree Controller in SourceView. SourceView shows a Split View with a tree structure on the left and either shows the contents of a URL or a List of Files on the right, depending on which item is selected in the left view.
>>>
>>> The SourceView project is built using ARC, but my App uses Manual Memory Management. When I moved the code over, I changed it to use release etc. and changed any properties or iVar’s to use retain or assign. The problem builds with no analyser warnings (which doesn’t mean as much as it used to, because I’ve found that the Analyser in XCode 6.3 is buggy).
>>>
>>> When I run the App, it displays the Tree View fine and Populates the two sections, but it crashes due to an over-release if I select a file based item - I found this by using NSZombies - it gives the error:
>>>
>>> *** -[NSImage release]: message sent to deallocated instance 0x20e5b9fc0
>>>
>>> I traced the problem down to the method copies below - please see comments in code. I’ve stopped it crashing by adding a retain although it doesn’t display the Files Correctly so there is something else wrong. I can’t figure out why I need this extra retain since everything seems to balanced without it.
>>>
>>> Any ideas how to debug this would be greatly appreciated.
>>>
>>> All the Best
>>> Dave
>>>
>>> - (void)outlineView:(NSOutlineView *)olv willDisplayCell:(NSCell*)cell forTableColumn:(NSTableColumn *)tableColumn item:(id) item
>>> {
>>> NSImage* iconImage;
>>> NSString* urlStr;
>>> ImageAndTextCell* myCell;
>>> ChildNode* myChildNode;
>>>
>>> if ([[tableColumn identifier] isEqualToString:COLUMNID_NAME] == NO)
>>> return;
>>>
>>> // we are displaying the single and only column
>>> if ([cell isKindOfClass:[ImageAndTextCell class]] == NO)
>>> return;
>>>
>>> iconImage = nil;
>>> myChildNode = [item representedObject];
>>> if (myChildNode != nil)
>>> {
>>> if (myChildNode.isLeaf == YES)
>>> {
>>> urlStr = myChildNode.urlString;
>>> if (urlStr != nil)
>>> {
>>> if ([myChildNode.urlString hasPrefix:HTTP_PREFIX])
>>> {
>>> myChildNode.nodeIcon = self.pURLImage;
>>> }
>>> else
>>> {
>>> iconImage = [[[NSWorkspace sharedWorkspace] iconForFile:urlStr] copy]; //Crashes without retain or if I remove the copy and and release statement below
>>>
>>> LogIfDave(@"Before Get File iconImage - retainCount: %ld",[iconImage retainCount]);
>>> myChildNode.nodeIcon = iconImage;
>>> //***** [iconImage release]; //** Crashes if Present!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
>>>
>>> LogIfDave(@"After set Item iconImage - retainCount: %ld",[iconImage retainCount]);
>>> }
>>> }
>>> }
>>> }
>>> else
>>> //**
>>> //** Check if it's a special folder (PLACES or BOOKMARKS), we don't want it to have an icon
>>> //**
>>> {
>>> if ([self isSpecialGroup:myChildNode])
>>> {
>>> myChildNode.nodeIcon = nil;
>>> }
>>> else
>>> {
>>> myChildNode.nodeIcon = self.pFolderImage;
>>> }
>>> }
>>>
>>> // set the cell's image
>>> [myChildNode.nodeIcon setSize:NSMakeSize(kIconImageSize,kIconImageSize)];
>>> myCell = (ImageAndTextCell*) cell;
>>>
>>> iconImage = myChildNode.nodeIcon;
>>>
>>> if (iconImage != nil)
>>> LogIfDave(@"Before set pTextCellImage - retainCount: %ld",[iconImage retainCount]);
>>>
>>> //*** This line causes a crash if the [iconImage release]; statement above is executed!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
>>>
>>> myCell.pTextCellImage = iconImage;
>>>
>>> if (iconImage != nil)
>>> LogIfDave(@"After set Item pTextCellImage - retainCount: %ld",[iconImage retainCount]);
>>> }
>>>
>>>
>>> _______________________________________________
>>>
>>> Cocoa-dev mailing list (email@hidden)
>>>
>>> Please do not post admin requests or moderator comments to the list.
>>> Contact the moderators at cocoa-dev-admins(at)lists.apple.com
>>>
>>> Help/Unsubscribe/Update your Subscription:
>>>
>>> This email sent to email@hidden
>>
>>
>> _______________________________________________
>>
>> Cocoa-dev mailing list (email@hidden)
>>
>> Please do not post admin requests or moderator comments to the list.
>> Contact the moderators at cocoa-dev-admins(at)lists.apple.com
>>
>> Help/Unsubscribe/Update your Subscription:
>>
>> This email sent to email@hidden
>
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden