Search code examples
objective-cmemory-managementcocos2d-iphoneretain

I’ve set my property to retain, am I supposed to release it even if it is set to autorelease?


Let us say we have some code that looks like below:

@interface SomeClass : NSObject
@property (nonatomic, retain) NSString *someString;
@end

@implementation SomeClass
@synthesize someString;
-(id)init {
    if (self=[super init]) {
        someString = [NSString stringWithString:@"some string"];
    }
    return self;
}
@end

Am I supposed to release the someString property in the dealloc method of SomeClass, even if someString was set to autorelease and I never actually retained it in my init method? If so, I'd simply add [someString release] before [super dealloc] in the -release method. Correct?

Now the real issue I am having is that while using Cocos2D, I've reached a contradicting situation. My code looks like below:

@interface SomeLayer : CCLayer
@property (nonatomic, retain) CCSprite *someSprite;
@end

@implementation SomeLayer
@synthesize someSprite;
-(id)init {
    if (self=[super init]) {
        someSprite = [CCSprite spriteWithFile:@"SomeFile.png"];
        [self addChild:someSprite];
    }
    return self;
}
@end

Now, I have added someSprite as a child to my layer SomeLayer. So, what should I do to make sure I have no memory leaks here? I could think of the following:

  1. Obviously, I'd think of calling [someSprite release] in SomeLayer's -dealloc method. but it gives me EXC_BAD_ACCESS in [super dealloc] (the next line). Most likely because I didn't remove the child, and the superclass tries to access the child that I just released.
  2. I call [self removeChild:someSprite cleanup:YES] in the -dealloc method, which would remove the child and also release it. So I do not need to follow up with [someSprite release]. But hey, the -dealloc method of the superclass CCNode already does all that for me.
  3. I do nothing. I wouldn't override the -dealloc method at all. Well, this seems to work fine, but it contradicts the statement: "if you retain something, you're supposed to release it".

Any help on why I must release the object in case I, and why not in case II at an early stage would help save a lot of memory related issues in the long run.

Thanks


Solution

  • someString = [NSString stringWithString:@"some string"];
    

    This is wrong. You are keeping a pointer to an autoreleased object that will disappear soon, and when you’ll try to use the someString pointer bad things will happen. You should use the accessor ([self setSomeString:…]), retain the autoreleased value (someString = [… retain]) or use a method that returns a retained value (someString = [[NSString alloc] init…]).

    In your real use case you should do the same with the sprite, you are getting EXC_BAD_ACCESS because you over-release the sprite: you call release without ever retaining the value. Read the Cocoa Memory Management Guide, you will save yourself a lot of trouble in the long run.

    By the way, I think your main problem is that you think that a simple assignment to the someString variable retains the assigned value. That is not the case (not without ARC, to be more precise). Assignment to the instance variable is just that, a plain assignment. If you want to go through the accessors, you have to send a message ([self setSomeString:…]) or use the dot notation (self.someString = …).