views:

121

answers:

3

I fear I am being stupid.

I've spent about three hours tracking down a memory leak that's been destroying my sanity and after commenting out half my app I have come to the following conclusion.

Given the following in the right places.

NSString *blah;

@property (nonatomic, retain) NSString *blah;

@synthesize blah;

-(id)initWithBlah:(NSString*)b {

     self.blah = b;    //this leaks
     blah = b;         //this does not

}

I am not particularly experienced with objectice c, I understand that outside of the class if I were calling object.blah = b; I would be transparently calling a setter function which would retain the b. Inside the function I'm presuming by setting it with self.blah = b I'm double retaining for some reason?

Could someone explain to me why that's the case or if not what I might be doing wrong?

Cheers

A: 
blah = b

Modifies the class instance variable directly.

self.blah = b

will invoke the accessors if present - thus retaining, releasing resources as needed.

You should add [blah release]; to your dealloc method to free the resource when your class is released.

Paul Alexander
+1  A: 

You are mistaken. The blah = b; assignment makes little sense because after your code returns from initWithBlah: you can no longer rely on the string being around. Whenever you access it next, it has very probably already been deallocated.

The self.blah = b; assignment is correct because it calls the setter and thereby you take ownership of the string. Of course, you have to release blah in your -dealloc, too, to prevent memory leaks.

Ole Begemann
ahh thank you. I'd assumed for some reason that because the setter was transparently performing the retain that some piece of code would remember it's existence and transparently release it for me on destruction. Thanks that solves my problem.
dageshi
By the way, the convention is to use `@property (nonatomic, copy)` instead of `(nonatomic, retain)` for `NSString *` variables. With retain, another object could assign a mutable string to your property and then later modify the string's contents without your class noticing it, which breaks encapsulation.
Ole Begemann
A: 

Using the accessor is fine, if it leaks then something else is wrong.

In particular your initializer has to be called correctly, i.e. following the Cocoa Memory Management guidelines that parameters are not owned implicitly by the callee.

So the following would be fine as it passes an autoreleased string in:

YourObj *obj = [[YourObj alloc] initWithBlah:[NSString stringWithString:@"blah"]];

While the following leaks due to passing in a retained string:

YourObj *obj = [[YourObj alloc] initWithBlah:[[NSString alloc] initWithString:@"blah"]];

Another thing you have to be aware of is that declared properties do not automatically take care of the clean-up, so be sure to handle that in -dealloc:

- (void)dealloc {
    self.blah = nil;
    // ...
}
Georg Fritzsche