0

Let say i have an class named as MyTestClass.h.

Class structure is look like

@interface MyTestClass : NSObject {

    NSString *testString;   
}

@property (nonatomic, retain)NSString * testString;

@end

.m file

@implementation MyTestClass

@synthesize testString;    

-(id) init{ 

    [self setTestString:@""];           
    return self;
}

-(void)dealloc{ 

    [self.testString release];      
    testString = nil;

    [super dealloc];
}

@end

Now i created an object of MyTestClass and assigned testString twice

MyTestClass * myTestClass = [[MyTestClass alloc] init];

[myTestClass setTestString:@"Hi"];
[myTestClass setTestString:@"Hello"];

Now i think, two times my testStrings memory is leaked!! (one through init() and another one through my first setTestString method)

Am i correct? or will @property (nonatomic, retain) handle/release previous allocated memory?

or ,in this kind of cases ,will i need to override the setTestString() in MyTestClass.m like below code

-(void)setTestString:(NSString *)tempString{    

    [testString release];
    testString = nil;

   testString = [tempString retain];
}

Any help on this question is appreciated.

Thanks.

JeremyP
  • 84,577
  • 15
  • 123
  • 161
Shamsudheen TK
  • 30,739
  • 9
  • 69
  • 102
  • You aren't leaking any that I can see - although I use ARC. To my knowledge, you'd only be leaking in this situation if you created an assignment variable and then didn't release it before your method ended. – Dustin Jul 05 '12 at 14:59
  • Note that your `dealloc` method could also be simplified to `self.testString = nil;` before the call to `super`, which will use the auto-generated setter automatically release the previous value of testString. – Turix Jul 05 '12 at 15:02
  • apple documentation specifically states not to use accessors in the init and dealloc methods. was hoping to quote documentation but cant find it at the moment, this will have to do http://stackoverflow.com/questions/192721/why-shouldnt-i-use-objective-c-2-0-accessors-in-init-dealloc – owen gerig Jul 05 '12 at 15:08
  • you mean that just writing " @property (nonatomic, retain)NSString * testString;" and "@synthesize testString;" will automatically handle all the memory management.. am right? if no, then where i release the properties? – Shamsudheen TK Jul 05 '12 at 15:41

6 Answers6

2

Any help on this question is appreciated.

I'll take this as a licence to make sone observations not necessarily directly related to your question.

Firstly, if you declare a retain property (as you have done) and synthesize it, the automatically generated getters and setters handle memory management correctly for you.

If you manually create setter (which you are allowed to do even with an @synthesize existing), you have to do the memory management yourself. Use either of trojanfoe's examples.

The setter in your question contains a bug in that if testString == tempString i.e. you assign the value of the property to itself, you could end up with assigning a dangling pointer to the property because you effectively release tempString and then retain it.


This is an implementation detail that you an safely ignore, but string literals e.g. @"blah" are compiled into the executable and will never be deallocated no matter how many times they are released. So, with your example, even if the setter did not do correct memory management, there will be no leak.


By the way, the normal pattern for an init method is

-(id) init
{
    self = [super init];
    if (self != nil)
    {
        // init stuff
    }
    return self;
}

or logical equivalent.

You should get into the habit of using it because you need to call the super class's init method and it is allowed to change the value of self, even to nil.

Also, while it is very good practice normally to set the object reference to nil after releasing it, in both cases when you do it, it is unnecessary. the first time, the variable is about to go out of scope and the second time you immediately assign it from some other object.

JeremyP
  • 84,577
  • 15
  • 123
  • 161
0

It's not a leak. Synthesized variable are correctly handled.

A synthesized method is implemented in this way (for a retain keyword)

@property (nonatomic, retain) NSString *string;
//backed by variable NSString *_string;

- (void)setString:(NSString*)newString
{
    if (newString != _string) {
       [_string release];
       _string = [newString retain];
    }
}

Of course this is a leak:

- (void)aMethod //of my class with string property
{
   NSString *aString = [[NSString alloc] initWithString:@"hello"];
   self.string = aString; //retain count of 2
   self.string = @"hello2"; //retain count of 1 for aString

  //now I don't release aString.... leak

}
Francesco
  • 1,840
  • 19
  • 24
  • is your mentioned that @property (nonatomic, retain) will handle/release previous allocated memory. i dont want to implenet the setTestString method. am i right? – Shamsudheen TK Jul 05 '12 at 15:22
  • Yes.. you don't need to implement it. I did it only to show you how it is implemented the method (and how it was implemented before the introduction of properties...)... so.. simply write the couple `@property` and `@synthesize` and you are ok! – Francesco Jul 05 '12 at 15:29
0

If you use the auto-generated setter (in your case, setTestString:, which is also called by self.testString = ...;), the previous value of a retain property is released before being set. So no, there is no leak in the code you posted above.

Turix
  • 4,470
  • 2
  • 19
  • 27
0

The synthesized setter method should do the right thing. Here's an example of it's implementation:

- (void)setTestString:(NSString *)tempString
{    
    [tempString retain];
    [testString release];
    testString = tempString;
}

or:

- (void)setTestString:(NSString *)tempString
{    
    if (tempString != testString)
    {
        [testString release];
        [tempString retain];
        testString = tempString;
    }
}
trojanfoe
  • 120,358
  • 21
  • 212
  • 242
  • The one that's actually used is the bottom one. Either is valid, but the bottom one gives you a marginal performance benefit since no expensive retains and releases are done if tempString == testString. – JeremyP Jul 05 '12 at 15:01
  • is your mentioned that @property (nonatomic, retain) will not handle/release previous allocated memory. i have to implement the setTestString method to mange memory. am i right? – Shamsudheen TK Jul 05 '12 at 15:25
  • @Ramshad No, using the `retain` property attribute generates code similar to the methods I have mentioned in my answer. – trojanfoe Jul 05 '12 at 15:26
0

the dealloc is only called when the instance is destructed. if you do :

[myTestClass setTestString:@"Hi"];
[myTestClass setTestString:@"Hello"];

in the same block, you're juste calling twice the setter. there is no memory leak.

OthmanT
  • 223
  • 3
  • 13
0

When you use @synthesize on a property that specifies retain, the setter that's generated will handle the retain/release correctly for multiple assignments. As long as you use self. rather than going directly to the backing variable and do a final release in dealloc you should be fine.

Phillip Mills
  • 30,888
  • 4
  • 42
  • 57