views:

413

answers:

5

When stepping with the debugger through this, dfString is invalid after [df release]

- (NSString*)dateFormatStringWithLocale:(NSLocale*)locale {
    NSDateFormatter* df = [[NSDateFormatter alloc] init];
    [df setDateStyle:NSDateFormatterShortStyle];
    [df setTimeStyle:NSDateFormatterShortStyle];
    [df setLocale:locale];
    NSString *dfString = [df dateFormat]; // dfString now contains nice date format
    [df release]; // seems to also kill dfString ???
    return dfString; // dfString is invalid here
}

Let's think about it: dfString is an object, just like any other. I ask for a string from df, with [df dateFormat]. I don't own that string, though, so I don't have to release it. But I own df, so I release it. Now lets assume that string I get from [df dateFormat] is some ivar of df, and gets -release'd in -dealloc of df. Then that damn string is gone. But when I call -retain on that dfString, which is just a pointer to the string owned by df, then damn df won't get released. So, what do I do? copy the string and autorelease it?

+2  A: 

Set the NSDateformatter to autorelease:

NSDateFormatter *df = [[[NSDateFormatter alloc] init] autorelease];

And then remove the release

[df release];  //  Remove this line

That way you're returning a fully autoreleased object as is the convention in an instance method in obj-c

h4xxr
I don't think that's right. He's not returning df so there's no need for it to be autoreleased.
Stephen Darlington
I don't think you need to keep all of df around if all you need is one of its instance variables (properties).
mahboudz
+1  A: 

I think your understanding of how it's supposed to work is correct and (by inspection at least) your code looks right too.

My guess is that the debugger is not telling the whole truth, perhaps related to compiler optimisation levels or similar.

Stephen Darlington
indeed i had a bug in code. the relase of df caused the string to go to nirvana.
HelloMoon
+2  A: 

I'd do as you say, make an autoreleased string, either like this:

NSString *dfString = [NSString stringWithString: [df dateFormat]];

or like that:

NSString *dfString = [[[df dateFormat] copy] autorelease];

I prefer the first one but please correct me if there's anything wrong with it.

Ölbaum
This should work, but you could just as easily take ownership of the original string so df doesn't trash it.
mahboudz
+1  A: 

Try this:

NSString *dfString = [[df dateFormat] retain];

Since dfString is probably in instance variable of dfString, it is getting dealloc'ed when df is released. Try just retaining dfString. In dealloc, its retainCount goes down by one, but it won't be released completely since you now have ownership. See if that helps.

mahboudz
You do have to release this when you are done, or you can mark this as autorelease, but then you have to be done with it before the end of the runloop.
mahboudz
A: 

It's a question of ownership. The formatter owns the string you are looking at. Thus the string dies once the formatter goes away. You should somehow claim ownership of that string using copy or retain.

This actually depends on how the accessor method is implemented. Both implementations below are perfectly valid:

  • (NSString*) dateFormat { return dateFormat; }

  • (NSString*) dateFormat { return [[dateFormat copy] autorelease]; }

Actually the first one only appropriate if you can be sure dateFormat is an immutable NSString. I.e. if you created a copy of whatever string you were handed. Otherwise, the caller may be tempted to make changes to a string you own.

Pierre Bernard