Why NSString variable needs to be retained?

374 views Asked by At

I have the following code in my .h file:

@interface Utils : NSObject {
    NSString *dPath;
}    
@property(nonatomic, retain) NSString *dPath;

And in my .m file:

    NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
dPath = [[documentPaths objectAtIndex:0] stringByAppendingPathComponent:kDatabaseName];
[dPath retain]; 

Why do I have to retain dPath if it's already defined as (nonatomic, retain)? If I don't add the [dPath retain]; I get some strange, random errors and the application crashes when using this variable in other functions. I guess that's because of some autorelease somehere but I don't have any.

So, what is the (nonatomic, retain) doing anyway? Is it really necessary the [dPath retain]; or am I just hiding something else with that?

3

There are 3 answers

3
BoltClock On BEST ANSWER

Because the code isn't calling the dPath property's setter method, it's just setting the instance variable dPath directly:

dPath = [[documentPaths objectAtIndex:0] stringByAppendingPathComponent:kDatabaseName];
[dPath retain]; 

So it has to be retained manually.

You will be able to (in fact you need to) omit the retain call if the property setter was used like this (notice the self.):

self.dPath = [[documentPaths objectAtIndex:0] stringByAppendingPathComponent:kDatabaseName];

or like this (notice the setDPath:):

[self setDPath:[[documentPaths objectAtIndex:0] stringByAppendingPathComponent:kDatabaseName]];

The setter retains the NSString for you so you don't have to do it yourself.


A nice little practice to follow in order to avoid the confusion, is to affix an underscore to your ivar name to indicate it's an ivar:

    NSString *dPath_;

Then synthesize your property like this, to associate it with your differently-named ivar:

// self.dPath is the property, dPath_ is the ivar
@synthesize dPath = dPath_;

Then modify your dealloc method, as well as any other code that directly references the instance var, to use the affixed name instead:

- (void)dealloc {
    [dPath_ release];

    [super dealloc];
}
0
Jinah Adam On

try setting and getting it with

self.dPath
0
hotpaw2 On

If you want to call the property setter method, which will invoke the retain, then you want to write:

self.dPath = ...

Jamming stuff into a variable with:

dPath = ...

completely ignores the properties of this instance variable. Which is why you ended up needing to do the retain manually.