Lefora Free Forum
Loading
630 views

To retain or not to release - maybe a bug?

Page 1
1–5
rookie - member
4 posts





The simple function below shows that NSImage initWithData increments the data retaincount by 1, but when NSImage itself is released the data retaincount is not decremented. Is this the behavior to be expected by all objects, or is this a bug?

bool isImage(NSData *data){
    NSLog(@"%i", [data retainCount]); //This prints 1
  NSImage *image = [[NSImage alloc] initWithData:data];
  NSLog(@"2: %i", [data retainCount]); //This prints 2, NSImage holds reference
    bool ret = false;

    if(image)
        ret = true;

  [image release];
  NSLog(@"%i", [data retainCount]); //This prints 2, NSImage is gone but retain count is the same 
  [data release];
    NSLog(@"4: %i", [data retainCount]); //This prints 1, had to release it myself
    return ret;
}


Thanks


?
288 posts


I agree that this looks very suspicious - however I think it's unlikely to be a bug because this kind of fundamental thing in Obj/C are unlikely to have such an obvious error.  I also can't see how the image you allocated wouldn't be dealloc'd when you released it. So several thoughts come to mind:

1) Do you have garbage collection enabled?
2) Can you also printing the retainCount on [image retainCount] in the NSLog(@"2..."); statement
3) Subclass NSImage as MyImage and put NSLog's in its dealloc/release/retain methods to monitor.

This is rather curious.

__________________
rookie - member
4 posts

Objective C Garbage Collection is set to "Unsupported" in Target->Build->GCC 4.2 Code Generation.

So i think it is disabled.


bool isImage2(NSData *data){
  NSLog(@"data: %i", [data retainCount]);

  NSImage *image = [[NSImage alloc] initWithData:data];

  NSLog(@"data: %i, image: %i", [data retainCount], [image retainCount]);

  bool ret = false;

  if(image)
     ret = true;

  NSLog(@"data: %i, image: %i", [data retainCount], [image retainCount]);

  [image release];

  //NSLog(@"data: %i, image: %i", [data retainCount], [image retainCount]); // CRASH!!!
  NSLog(@"data: %i", [data retainCount]);

  [data release];

  NSLog(@"data: %i", [data retainCount]);


  return ret;
}

This gives:

2010-05-12 09:59:23.903 ImageOrganizer02[1439:903] data: 1
2010-05-12 09:59:23.903 ImageOrganizer02[1439:903] data: 2, image: 1
2010-05-12 09:59:23.907 ImageOrganizer02[1439:903] data: 2, image: 1
2010-05-12 09:59:23.908 ImageOrganizer02[1439:903] data: 2
2010-05-12 09:59:23.908 ImageOrganizer02[1439:903] data: 1

Very odd behavior.

?
288 posts

Thanks for running these tests. This is really curious - I'll look at this after work this evening.  I had something like this a few weeks ago - and I exploded on the equivalent of your final NSLog (because data really was released!).  I wonder who's got the unexplained retain.  This is curious.

__________________
?
288 posts

I've found a fix, however I'm not certain why it works.  For sure it has something to with the NSAutoreleasePool.  I've modified your code a little and run from a command-line program.  The result is correct, the retain count is 1 at the end.

I think while you have an autorelease pool in place, you shouldn't release objects that you alloc.  You can see that I get a warning from main() when I alloc.

There is a paper on apple.com about memory management in cocoa.  I think we're both going to have to visit that to unpuzzle this.  http://developer.apple.com/mac/library/documentation/cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html

bool isImage(NSData *data)
{
bool result = false ;
if ( !data ) return result ;

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    NSLog(@"1: %i", [data retainCount]); //This prints 1
    NSImage* image = [[NSImage alloc] initWithData:data];
    NSLog(@"2: %i", [data retainCount]); //This prints 2, NSImage holds reference

    if( image )
{
result = true;
[image release];
}
    NSLog(@"3: %i", [data retainCount]); //This prints 1, had to release it myself
    [pool drain];

    return result;
}

int main (int argc, const char * argv[])
{
//    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int result = 0 ;
if ( argc < 2 ) {
printf("syntax: TestImageRetain pathToImage\n") ;
result = 1 ;
} else {
const char* filename = argv[1] ;

NSString* path = [NSString stringWithFormat:@"%s",filename];
NSString* imagePath = [path stringByExpandingTildeInPath];
NSData* data = [NSData dataWithContentsOfFile:imagePath];

NSLog(@"imagePath = %@ result = %s",imagePath,isImage(data)?"YES":"NO") ;

NSLog(@"4: %i", [data retainCount]); //This prints 2, NSImage is gone but retain count is the same 
[data release];
}
//    [pool drain];
    return 0;
}


2010-05-12 23:16:44.104 TestImageRetain[26287:a0f] *** __NSAutoreleaseNoPool(): Object 0x1001152a0 of class NSCFString autoreleased with no pool in place - just leaking
2010-05-12 23:16:44.107 TestImageRetain[26287:a0f] *** __NSAutoreleaseNoPool(): Object 0x100119050 of class NSPathStore2 autoreleased with no pool in place - just leaking
2010-05-12 23:16:44.113 TestImageRetain[26287:a0f] *** __NSAutoreleaseNoPool(): Object 0x1001156d0 of class NSConcreteData autoreleased with no pool in place - just leaking
2010-05-12 23:16:44.113 TestImageRetain[26287:a0f] 1: 1
2010-05-12 23:16:44.132 TestImageRetain[26287:a0f] 2: 2
2010-05-12 23:16:44.132 TestImageRetain[26287:a0f] representations count = 1
2010-05-12 23:16:44.133 TestImageRetain[26287:a0f] 3: 2
2010-05-12 23:16:44.133 TestImageRetain[26287:a0f] imagePath = /Users/rmills/R.jpg result = YES
2010-05-12 23:16:44.134 TestImageRetain[26287:a0f] 4: 1

__________________
Page 1
1–5

Locked Topic


You must be a member to post in this forum

Join Now!