Question

When an instance method returns a value that was initialized with a convenience constructor, do I need to retain that object and then autorelease in the return so that when the convenience constructor's autorelease occurs, it doesn't remove the object.

Will this release description before the calling code and take ownership with a retain or something?

- (NSStringMutable *)test {
    NSMutableString *description = [NSMutableString stringWithString:@"Test Value"];
    return description;
}

Or should it be like this?

- (NSStringMutable *)test {
    NSMutableString *description = [NSMutableString stringWithString:@"Test Value"];
    [description retain];                               
    return [description autorelease];
}

Calling Code:

NSMutableString *testVar = [[NSMutableString alloc] initWithString:[object description]];
Was it helpful?

Solution

No, you should be fine with:

- (NSStringMutable *)test
{
    return [NSMutableString stringWithString:@"Test Value"];
}

This will leave the the object with a retain count of 1 and will be in the autorelease pool.

The autorelease pool is drained at specific times - it's not like a garbage collector. If you're implementing an event handler (like a button clicked handler), the autorelease pool is drained by the framework when you return from your event-handling code.

If you had used this:

- (NSStringMutable *)test
{
    NSMutableString *description = [NSMutableString stringWithString:@"Test Value"];
    [description retain];                                                               
    return [description autorelease];
}

...then the object would have a retain count of 2 and would be in the autorelease pool twice, and would actually behave in the same way as in the previous code example.

OTHER TIPS

You can just return it. This is one of the main purposes of autorelease. Unless you've set up an autorelease pool of your own, the pool won't be drained until the next run through the event loop. The memory management programming guide explains all this in good detail — you should read that until you feel comfortable with it.

Side note: If this weren't safe and the autorelease pool were going to be drained early for some bizarre reason, giving it two retains and two autoreleases wouldn't make a difference. The numbers are still balanced, so it's still going to be released out of existence at some point.

I've already voted on the correct answer, I'm adding this as a style note:

Your calling code isn't going to work, because it is calling [object description] when it should be calling [object test]

You don't need to be returning mutable strings unless you really want to be able to change the string. I personally try to minimise mutability in the code I write because I feel it is easier to maintain programs where state changes are minimal. You are only returning a description so I don't think it needs to be mutable. I know this is only some example code so maybe I'm being too picky

You could rewrite this as:

-(NSString *)description {
    // Just return a static NSString. No need to worry about memory management.
    return @"Test Value";
}

And if you want to be able to change the value of this returned string in your calling code:

NSMutableString *testVar = [[NSMutableString alloc]initWithString:[object description]];

Since you've called alloc on this string, you own it and are responsible for releasing it at some future date.

Alternatively, you can use one of my favourite bits of code:

NSMutableString *testVar = [[object description] mutableCopy];

This will return a mutable copy of even an immutable object (if it conforms to the NSMutableCopying protocol, of course). And you need to send [testVar release] at some stage.

And to tie this in as an actual answer to your question: if you send alloc, copy, mutableCopy, or retain to an object, then you own the object and are responsible for sending it a release message. You can assume that anything else returns an autoreleased object.

Again, I know this is only a quick bit of sample code that you asked a question on, but if you follow the above rule you've got most of your memory management problems sorted. In your first example you sent none of these for messages, so you don't need to release any memory yourself. However, you have an alloc in your calling code, so you own testVar and you need to release it.

No, you can simply return the autoreleased value. The reason for this is that autorelease isn't a function of the variable itself, it's a function of the autorelease pool, which (unless you create one yourself) is usually managed by the run loop.

You are close with the second one, but you don't need the retain for the case you are talking about here and in fact don't need to call autorelease yourself.

This is valid, since stringWithString will return an autoreleased object already:

 - (NSStringMutable *)test
 {
   return [NSMutableString stringWithString:@"Test Value"];        
 }

In general when creating objects using Objective-C if you are calling a convenience constructor (not calling alloc and init) the return value is always autoreleased so stringWithString returns an autoreleased object the you can just return.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top