views:

110

answers:

3

This is a followup question from a previous question, which is hopefully a little clearer. I am just curious how the code presented below is working, specifically is the variable myString getting released. It does not look like it is from the output?

CODE

// IMPLEMENT
@implementation CelestialBody
- (void)setName:(NSString *)newName{
    if(name != newName) {
     [name release];
     name = [newName copy];
    }
}
- (void)dealloc{
    [name release];
    name = nil;
    [super dealloc];
}
@end

.

// ------------------------------------------------------------------- **
// MAIN: 30th September 2009
// ------------------------------------------------------------------- **

#import <Foundation/Foundation.h>
#import "CelestialBody.h"

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    CelestialBody *newPlanet = [[CelestialBody alloc] init];
    NSString *myString = [[NSString alloc]initWithFormat:@"go home"];
    NSLog(@"RetainCount_1: %d",[myString retainCount]);

    [newPlanet setName: myString];
    NSLog(@"RetainCount_2: Incremented by copy in setName"); 

    // Clean up
    NSLog(@"RetainCount_2: %d -Before Release",[myString retainCount]);
    [newPlanet release];
    [myString release];
    [pool drain];
    NSLog(@"RetainCount_1: %d -After Release",[myString retainCount]);
    return 0;
}
// ------------------------------------------------------------------- **

OUTPUT

Running…
2009-10-01 09:28:50.395 RetainCount_1: 1
2009-10-01 09:28:50.399 RetainCount_2: Incremented by copy in setName
2009-10-01 09:28:50.399 RetainCount_2: 2 -Before Release
2009-10-01 09:28:50.400 RetainCount_1: 1 -After Release
Debugger stopped.

I am currently re-reading the Memeory Management Guide to try and see what I have missed.

many thanks

EDIT

Just added a the release to the dealloc, It looks like that was what I was missing.

- (void)dealloc{
    [name release];
    name = nil;
    [super dealloc];
}

gary

+1  A: 

I guess [newName copy] doesn't actually copy the NSString, because NSString is immutable? I never thought about this, but it makes sense to me.

At the end of your program you're releasing newPlanet and myString. My question is, are you releasing the instance variable name in the -dealloc method of CelestialBody? If you're not, then I believe you're leaking memory there.

  1. Create myString: the NSString's retainCount is 1
  2. [newPlanet setName:]: the NSString's retainCount is 2
  3. [newPlanet release]: the NSString's retainCount is 2 ? I guess you're not releasing it in -dealloc.
  4. [myString release]: the NSString's retainCount is 1
Thomas Müller
“I guess [newName copy] doesn't actually copy the NSString, because NSString is immutable?” Correct, but don't worry about that, or retain counts. Retain counts can be very misleading, partly because of optimizations like this. As long as you follow Cocoa's object-management rules, you're unlikely to have a problem.
Peter Hosey
+3  A: 

is the variable myString getting released.

[myString release];

All signs point to yes.

It does not look like it is from the output?

NSLog(@"RetainCount_2: %d",[myString retainCount]);
[myString release];

Your NSLog statement's output doesn't reflect the release message because the release message hasn't happened yet.

Also, don't worry about retain counts. They can be very misleading. As long as you follow Cocoa's rules and don't create any ownership cycles (A owns B owns C owns A), you'll rarely have a problem.

Peter Hosey
Sorry my mistake, I have updated the code.
fuzzygoat
+1. Do NOT worry about retain counts. IMO, Apple should remove the retainCount method altogether. It's too tempting for beginners to think they can rely on it rather than just learning the rules.
Chuck
Could not agree more about not worrying about specific retain counts. For example, if you had made `myString` an `NSMutableString`, the retain count would still be 1 after `setName:`. Why? Because `copy` makes a wholly new object when copying mutable objects. It `retain`s immutable objects because there's little point in copying things whose values can't change. It doesn't matter what the retain count is; just follow the rules and you'll always be fine.
Alex
Interesting Alex, I did not know that copying a NSMutableString makes a new copy, good to know, makes sense really.
fuzzygoat
fuzzygoat: That's the purpose of the `copy` method. Implementations that don't make a copy are the exceptions. They only exist where the object must be “copyable” (as a string must be), but actually copying it wouldn't be useful (as is true of an *immutable* string).
Peter Hosey
+2  A: 

This is not an answer to your question, per se, but an explanation of what you're seeing: The last call to retainCount is sent to a deallocated object, which is undefined behavior. The object happens not to have been overwritten yet, so it still kindasorta "works" in the sense that the method dispatch can still see the old data that's there and doesn't realize it's invalid. You will never get back 0 from calling retainCount, because such an object can't exist.

Chuck