views:

71

answers:

2

I am a little curious about the last lines in the two examples presented below (i.e. planetName = [value ??????]) My understanding is that the 1st example with the copy is best as that takes a copy of the string object to protect against the original string object being changed elsewhere.

I am also a little confused by the last line in the 2nd example, again my understanding was that the value object was being passed into the method, I guess I am confused as value is being retained with no associated release? Can someone set me straight?

- (void)setPlanetName:(NSString *)value {
    if (planetName != value) {
        [planetName release];
        planetName = [value copy];
    }
}

.

- (void)setPlanetName:(NSString *)value {
    if (planetName != value) {
        [planetName release];
        planetName = [value retain];
    }
}
A: 

in the class's dealloc method, there should be another [planetName release] there, which will handle releasing of any instance variables. If that is present then there is no memory leak to worry about.

As for your other question, yes copy is used if you potentially have a mutable object that you don't want to allow other code to be able to modify what your class expects. You are expected to release any object that you call copy on, as it returns something with a retain count of 1. Also, in the case of immutable objects (like NSStrings vs. NSMutableStrings) copy just calls retain since there is no need to make a full copy of something that is immutable.

Kevlar
Am I right in thinking that in the first version (with the copy) that if value is a string literal (i.e. @"TanTooine") then its released automatically, if on the other hand value is an object then its simply left to what created it outside the method to do the release?
fuzzygoat
if it's a string literal, calling copy on it effectively retains it (since string literals are immutable), so it is not automatically released until the class that owns that string is dealloc'd
Kevlar
+1  A: 

Given:

- (void)setPlanetName:(NSString *)value {
    if (planetName != value) {
        [planetName release];
        planetName = [value copy];
    }
}

The -copy ensures that if someone passes in an instance of NSMutableString as value, then planetName won't change in your instances out from under you.

A good defensive programming pattern. Note that -copy is free on immutable strings; -copy just bumps the retain value and returns self (the instance of the string that was copied).

Now, consider your second example:

- (void)setPlanetName:(NSString *)value {
    if (planetName != value) {
        [planetName release];
        planetName = [value retain];
    }
}

Perfectly valid and works fine, just not as defensive.

In both cases, planetName must be released in your -dealloc method.

- (void) dealloc
{
    [planetName release];
    planetName = nil; // defensive
    [super dealloc];
}

It doesn't matter if the string is copied, retained, or was originally a constant string that was passed into your setter. If you retain it (or implied retain it through copy), you must release it.

Note that you can think of this as "escape patterns". Whenever the existing value of planetName escapes your object, you must release it. That can happen when the object is deallocated or when a new value of planetName is set, hence the -release in the setters.

Or, if on Mac OS X, you could turn on garbage collection and be done with it. In any case, you should be using @property & @synthesize to automatically generate the getter/setter pair.

bbum
Initially I want to avoid garbage collection to better understand how things are working, thats also primarily the reason that (initially) I am not using property and synthesize. Thanks for the help, much appreciated.
fuzzygoat
Just curious, if in the first version, I am using a constant string @"Earth" for value you mentioned that the copy bumps the retain value, in this case would that be to 2? If so how are they released, my guess is with a string constant one is stored in the data segment and does not need to be released, the other is the one that we ultimately release from the dealloc method? Just asking as you first have "value" and then you make a copy, so thats 2, unless I am wrong.
fuzzygoat
In short, don't worry about it and don't bother with the retain count; the value of it at any given point in time is an implementation detail. Just make sure the retains you caused are balanced by releases in your code.
bbum