views:

157

answers:

4

Whenever I need to create a new NSString variable I always alloc and init it. It seems that there are times when you don't want to do this. How do you know when to alloc and init an NSString and when not to?

+3  A: 

If you want to initialise it to a known value, there is little point in using alloc, you can just use a string literal:

NSString* myStr = @"Some value";

If you want to initialise it with a format or whatever, but don't need it to stick around beyond the current autorelease pool lifetime, it's a bit neater to use the class convenience methods:

NSString* myTempStr = [NSString stringWithFormat:@"%d", myIntVar];

If you need its lifetime to go beyond that, either alloc/init or else add a retain to the previous call. I tend to slightly prefer the latter, but the two are pretty much equivalent. Either way you will need a balancing release later.

Note that, since NSString is not mutable, this sort of thing is not only unnecessary but actively wrong:

// don't do this!
NSString* myStr = [[NSString alloc] initWithString:@""];
myStr = someOtherStr;

since it leaks the initial placeholder value.

walkytalky
How do you know what the current autorelease pool lifetime is?
awakeFromNib
@awakeFromNib By reading the [relevant section](http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html) of the memory management docs. Commonly you can think of an autoreleased object as lasting until you let it out of your sight, and then just a teensy bit longer (ie, long enough to be a valid return value). If you are creating stuff in a loop you may want to manage an autorelease pool of your own to avoid building up a huge pile of unreleased allocations, but the default should be fine for a handful of strings during event handling.
walkytalky
+1  A: 

I'm guessing that you are referring to using StringWithString or similar instead of initWithString? StringWithString alloc and inits for you under the hood and then returns an autoreleased string.

If you don't need to do any string manipulation other than to have the string, you can use NSString *str = @"string";

In general with iOS, the tighter you manage your memory the better. This means that if you don't need to return a string from a method, you should alloc init and then release it.

If you need to return a string, of course you'll need to return an autoreleased string. I don't think its any more complicated than that.

Ross
Nope. He's referring to this: http://stackoverflow.com/questions/3796312/why-doesnt-this-code-produce-the-correct-output/3796955#3796955
Peter Hosey
+4  A: 

Whenever I need to create a new NSString variable I always alloc and init it.

No, that doesn't make sense.

The variable exists from the moment the program encounters the point where you declare it:

NSString *myString;

This variable is not an NSString. It is storage for a pointer to an NSString. That's what the * indicates: That this variable holds a pointer.

The NSString object exists only from the moment you create one:

[[NSString alloc] init];

and the pointer to that object is only in the variable from the moment you assign it there:

myString = [[NSString alloc] init];
//Or, initializing the variable in its declaration:
NSString *myString = [[NSString alloc] init];

Thus, if you're going to get a string object from somewhere else (e.g., substringWithRange:), you can skip creating a new, empty one, because you're just going to replace the pointer to the empty string with the pointer to the other one.

Sometimes you do want to create an empty string; for example, if you're going to obtain a bunch of strings one at a time (e.g., from an NSScanner) and want to concatenate some or all of them into one big string, you can create an empty mutable string (using alloc and init) and send it appendString: messages to do the concatenations.

You also need to release any object you create by alloc. This is one of the rules in the Memory Management Programming Guide.

Peter Hosey
+1  A: 

It seems that there are times when you don't want to do this.

I can't think of any time when I would want to alloc/init a NSString. Since NSStringgs are immutable, you pretty much always create new strings by one of:

  • convenience class method e.g.

    NSString* foo = [NSString stringWithFormat:...];
    
  • literal

    NSString* foo = @"literal";
    
  • NSString instance method

    NSString* foo = [bar uppercaseString];
    
  • copy from mutable string

    NSString* foo = [mutableBar copy];  // foo needs to be released or autoreleased in this case
    
JeremyP
You might want to read a file and stash it in an instance variable, in which case you'd use `initWithContentsOfFile:encoding:error:`. (Or `stringWith…` and `retain`, but that's no more efficient for you or the program.)
Peter Hosey
@Peter Hosey: I'd use the convenience class method in that case.
JeremyP