Search code examples
iphoneobjective-cnsstringretainautorelease

Why NSString variable needs to be retained?


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?


Solution

  • 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];
    }