tags:

views:

27

answers:

2
- (void)createAString:(NSString **)str
{
   *str = [NSString stringWithString:@"Hi all!"];
   [*str autorelease]; // ???? is this right ?
}

How should I use release or autorelease ? I don't want to release outside of the function of course :)

...
NSString *createStr;
[self createAString:&createStr];
NSLog(@"%@", createStr);
A: 

Instead of using a double pointer, would it not be more elegant to use an NSMutableString instead?

- (void)createAString:(NSMutableString *)str
{
    [str setString:@"Hi all!"];
}

....

NSMutableString *createStr = [[NSMutableString alloc] init];
[self createAString: createStr];
NSLog(@"%@", createStr);
[createStr release];

Or, even better, just have the createAString method return an NSString.

- (NSString *)createAString
{
    return @"Hi all!"; // this is autoreleased automatically
}

I wouldn't want to presume that your needs are this simple, though. =)

Marc W
Thank you for your answer... but as I mentioned I don't want to create the instance outside the function, because I don't need it all the times!my original needs are to use the functionality I asked for in a function like `-(int) terminalExec:(NSString *)execPath arguments:(NSArray *)args output:(NSString **)outString` where it executes a task in a terminal and returns the status (int) of the execution AND the terminal's output which sometime I need.so... not so simple needs :)Thanks again !
Vassilis MRF
That isn't really more elegant IMO. Requiring the caller to create a mutable object for you is a bit hackish and not usually done.
Chuck
No, it would be more elegant to take advantage of the fact that a method can return a value and use it to return the required string.
JeremyP
+2  A: 

You're correct that you'd generally want to return autoreleased (or the like) objects from out params when you use this form. Your assignment statement in the function that sets *str to a string:

*str = [NSString stringWithString:@"foo"];

is already doing the right thing, because that method returns an instance of NSString that the caller doesn't own. Just like you could return this string object from your function without any further memory management, you can set it as the outparam as you've done. Your second snippet showing the call site is fine.


This said, I'm worried about a few things in your code that you should be sure you understand:

  1. The value of str inside the method is still a **, and sending that a message (as you've done for the speculative autorelease) is nonsense. Be sure you fully understand doubly indirected pointers before using them too liberally. :) If you need to send str a message after creating it, send it to *str, which is what contains the NSString *.

  2. Setting an outparam like this when the function returns void is not idiomatic Cocoa. You would normally just return the NSString * directly. Outparams are rare in Cocoa. (Usually just NSErrors get this treatment from framework calls. Otherwise they conventionally use name like getString to differentiate them from normal get accessors which don't use the word "get".)

  3. I hope -stringWithString was just an example. That method is almost never used in practice, since it's equivalent (in this case) to just using a @"string literal" (although that would muddy your example).

quixoto
Thanks for your answer !!that `[str autorelease];` was misspelled :) of course it is `[*str autorelease];`I use a function to return more than one things:`-(int) terminalExec:(NSString *)execPath arguments:(NSArray *)args output:(NSString **)outString`and sometime i want the task's(terminal) output; sometimes not!I was just confused with release issues. Generally...if the caller owns the instance, lets say with `...=[[NSString alloc] init] how should I use release/autorelease ??thank you again !
Vassilis MRF
What do you mean exactly by "if the caller owns the instance" ? What are you doing with that instance?
quixoto
`-(int) terminalExec:(NSString *)execPath arguments:(NSArray *)args output:(NSString **)outString``{NSTask *task = [[NSTask alloc] init];``...``NSPipe *pipe = [NSPipe pipe];``...``NSData *data = [file readDataToEndOfFile];``NSString *string = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];``...``int status = [task terminationStatus];``[task release];``if(outString != NULL)``{ *outString = [[NSString stringWithString:string] autorelease];//??``}``return status;``}`as you can see `string` won't be autoreleased! So What should I do ?
Vassilis MRF
You should `release` it explicitly, inside the method, because you don't use it anymore after handing a reference to `stringWithString`. Regular rules apply: if you alloc/init it, release it or autorelease it. But once again, don't use stringWithString here. It doesn't achieve anything for you.
quixoto
Thank you man!it just became ...`...`` NSString *string = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];``...` ` [task waitUntilExit];``...`` if(outString != NULL) ``{`` *outString = [string autorelease];`` NSLog(@">>> %i", [*outString retainCount]);``}` `return status;`
Vassilis MRF
2 things: If the caller doesn't provide a an outstring, you're leaking the string, since the autorelease only happens inside the conditional. Secondly, be careful about logging `retainCount`. As you'll discover if you spend any time here, it's notoriously unreliable as a debugging tool.
quixoto
Done! :)I' ll keep that `retainCount` issue in mind!Thanks, thanks !!
Vassilis MRF