Question

I have found that if I alloc a new object inside a Class method and return it to main() it seems to cause a memory leak when I no longer want the object.

For example, here is a simple Class that includes a Class method that returns an instance of itself:

@interface Stinker : NSObject
{
    int a;
}
+(instancetype) makeAStink;
-(void) showThem;
-(void) setEm: (int) z;
@end

@implementation Stinker
-(void) showThem
{
    NSLog(@"%d",a);
}

-(void) setEm: (int) z
{
    a = z;
}

-(void) dealloc
{
    NSLog(@"Arrrgggggh!");
}

+(instancetype) makeAStink
{
    id temp = [[self alloc] init];
    return temp;
}
@end

Now if I create an instance directly from main():

Stinker *aStink =[[self alloc] init];

and subsequently set aStink to nil:

aStink = nil;

the overridden dealloc method is called and the Argggggh! message is logged. That's fine and as expected.

But if I use the Class method I wrote to create an instance:

Stinker *aNewStink = [Stinker makeAStink];

the behaviour is different.

Now if I set aNewStink to nil, it will no longer point to the object but the object is not destroyed. dealloc is not called and the Arggggh message is not logged.

It seems like it still has an owner somewhere.

Of course when main() terminates the object is destroyed and dealloc is eventually called. But this seems to suggest that unused and unloved objects are still hanging around on the heap until the program terminates.

Isn't this a memory leak? Should I just avoid using Class methods to alloc new instances?

Was it helpful?

Solution

When using ARC, the following code

+(instancetype) makeAStink
{
    id temp = [[self alloc] init];
    return temp;
}

will be same with Non-ARC like this:

+(instancetype) makeAStink
{
    id temp = [[self alloc] init];
    return [temp autorelease];
}

Thanks to autorelease, aNewStink = nil will make aNewStink do release in next runloop.

So if you do this:

@autoreleasepool {
  Stinker *aNewStink = [Stinker makeAStink];
  aNewStink = nil;
}

Dealloc method is called immediately.

OTHER TIPS

this is MRC (without ARC) code for your example

+(instancetype) makeAStink
{
    id temp = [[self alloc] init];
    return [temp autorelease];
}

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

id obj = [Stinker makeAStink]; // obj is autoreleased object

id obj2 = [[Stinker alloc] init]; // obj2 is not autoreleased
[obj2 release]; // so you need to release it

[pool release]; // now obj is released and deallocated

so obj have an extra retain count which will be released (and deallocated) in next runloop whereas obj2 will be released immediately when release is called

this is not memory leak, it is usual behaviour and (normally) doesn't affect program performance in noticeable way

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top