Do NSString objects need to be alloc and init? - objective-c

Noob question:
I'm currently under the impression that when you want to create an object, you need to alloc and init that object.
However, I've seen seen several sample codes where an NSString object is declared, yet I see no alloc or init messages following...
A very simple example:
NSString *myString = #"Hello World";
NSLog(#"%#" , myString);
Can someone explain why this is so?

Declaring a variable does not require releasing any memory.
Instantiating objects does. And you only instantiate a new object if you call alloc or copy
In your example, you are setting your reference to the already existing object that the compiler creates from the hard-coded string. And you don't have to manage its memory because you didn't instantiate it.
I don't know if I'm explaining it clearly enough.
EDIT:
It looks like there is already a question that answers this:
Is a literal NSString autoreleased or does it need to be released?

When you embed an NSString literal in your code, such as #"hello, world', the compiler allocates space for it in your executable file and it's loaded into memory and initialized when your program starts.
Since it's part of your executable, it lives for the whole lifespan of your app. There's no need to retain or release it. The NSString *myString variable you create for it is a pointer to the place in memory where the compiler put the NSString literal.

Related

Does this cause leak of NSString?

I am a C programmer, but is pretty new to Objective-C. I've seen NSString-related code like this several times:
NSAppleScript* script = [[NSAppleScript alloc] initWithSource: #"<some script code>"];
...
[script release];
The above code explicitly releases the NSAppleScript object, but doesn't seem to release the NSString object anywhere.
I wondered if the [script release] automatically does the job of implicit release of the NSString object, so I changed the above code to the following:
NSString* scriptText = #"<some script code>";
NSAppleScript* script = [[NSAppleScript alloc] initWithSource: scriptText];
...
[script release];
//If [script release] has implicitly released scriptText,
//this would cause a repeated release.
[scriptText release];
But the above code turned out running also well. Does it mean that [script release] doesn't automatically release the NSObject object? In other words, does the code in the first section leak release of the NSString?
Very short answer: no. You shouldn't release scriptText. (In fact, you must not.)
In ObjC manual reference counting, you need to follow the rules, which are based on method names. If you call a method whose name begins with alloc or new or includes copy, then you are responsible for calling release or autorelease on the object that is returned to you. Also, if you call retain on an object, you are responsible to call release or autorelease.
Following the rules, you called +[NSAppleScript alloc], so you are responsible for calling release on the object returned to you. You did not call a retaining method to get scriptText; you used an NSString literal (#"..."). So you must not call release on it. It doesn't leak. (If it did, it would indicate a bug in Apple's code.)
The way this actually works is that NSString literals are stored directly in the binary, just like in C. There is no need to manage them, since they do not directly use memory. But this has nothing to do with your obligations under manual reference counting. You shouldn't think "this is a string literal so I shouldn't call release on it." That's not true at all. You should call release when the rules tell you to call release. It is completely correct to call retain on a value that happens to be a literal, and later call release on it. (This happens all the time. You generally don't know whether the NSString you're working with is a literal or not.)
It happens to be true that calling retain or release on NSString literals does nothing. They just ignore the call. Very short NSString objects don't even exist in memory. If they're short enough, the data is stored directly in the pointer (called a "tagged pointer"). Again, this is just an implementation detail. Your job is to follow the rules, not try to second-guess the system.
(The reason that your incorrect code with the extra release "works" is because literal NSStrings ignore memory management calls. The code is still incorrect. There's also no promise that over-releasing an object will cause a crash in any case, and it is very, very common when it does crash for it to occur at a random point, far away from the mistake. It's very common for objects to have pending autorelease calls on them, so you get a crash when the pool drains, with no hint where your bug is.)
And of course you should turn on ARC and let it handle it for you. It does a very good job. But it's helpful to understand the rules anyway. ARC uses the same name-based rules to figure out where to put retains and releases. That's how it can interoperate seamlessly with manual memory management.

Releasing an autoreleased string object doesnt crash

I have this basic question where when we try to allocate memory to a string by using alloc init and add it to autorelease pool, and then try to release it, it doesn't crash.
NSString *value = [[[NSString alloc] initWithString:#"Hello"] autorelease];
[value release];
If I do the same thing for a array, it crashes.
I just want to know how string is different from array since both inherit from NSObject.
Do you mean it doesn't crash right away?
I.e. in the debugger after stepping over the release line?
The Autorelease-Pool will not have triggered at that point so the auto-release operation is still outstanding.
Either way - As always with memory errors they might not crash
instantly,
on your machine/operating system,
with this specific built,
with your current build settings,
...
or even at all.
It's a programming error nevertheless.
It is not guaranteed that the program crashes. Unfortunally there are several errors that does not cause a crash (immediately).
However there is an optimization for string literals. They live eternally regardless of the way they are created, retained or released. -initWithString: can be smart enough not to return a new instance of NSString.
First, undefined behavior is undefined -- it is not guaranteed to crash or do any other specific thing. Over-release is undefined behavior.
Second, what is happening here is that string literals evaluate to a pointer to a statically-allocated string object which lives for the lifetime of the program. It is not dynamically-allocated, and thus is not subject to memory management. retain, release, etc. have no effect on it. [[NSString alloc] initWithString:...] (as well as [... copy]) on an immutable string object simply retains and returns its argument directly, since there is no need to create a new object. So [[NSString alloc] initWithString:#"Hello"] is the same as #"Hello".

How memory is managed for an object that is created but not assigned to any pointer?

This might be a stupid question, but it keeps bothering me.
Say if we have a method that takes an NSString object as its parameter and does something with the NSString object,
- (void)someMethod:(NSString *)str
{
//do something with str
}
Consider this code
[someObject someMethod:[[NSString alloc] initWithFormat:#"Hello World!"]];
Since alloc has been used in creating the string as parameter of someMethod, it has to be balanced by release no matter explicitly in pre-ARC environment or implicitly under ARC. But it seems there is no way we can get a pointer to the string as we have never assigned it to any pointer.
So my question is, first, is this way of passing parameter prohibited in writing objective c code? If no, then how objects created this way get released? And finally, does this code lead to memory leak?
Just for the record, I understand the above code is written
NSString *string = [[NSString alloc] initWithFormat:#"Hello World!"];
[someObject someMethod:string];
// [string release]; depending on ARC or non-ARC
Well, in fact, that object is assigned to the variable named str, which is a parameter of your method. You can manage the memory inside your method via that pointer, although methods aren't supposed to take ownership of their arguments (except see below).
ARC knows what to do in this situation -- it will either autorelease the object or add a release once the method is finished.
Under MRR, your snippet would be a leak; the correct way to avoid that is also to send autorelease:
[someObject someMethod:[[[NSString alloc] initWithFormat:#"Hello World!"] autorelease]];
or to use your last snippet (putting the string into a temporary variable and releasing later).
As a slightly esoteric option, it is possible for your method to declare that it owns the argument, by using the ns_consumed attribute:
- (void)someMethod:(NSString *) __attribute__((ns_consumed)) str;
This indicates that your method should send release to the object before it returns -- ARC will also take care of that.
So my question is, first, is this way of passing parameter prohibited in writing objective c code?
No. It's perfectly legal.
If no, then how objects created this way get released?
ARC will take care of it for you. If you do your own reference counting, then you can add it to the autorelease pool before it goes out of scope:
[someObject someMethod:
[[[NSString alloc] initWithFormat:#"Hello World!"] autorelease]];
^^^^^^^^^^^
And finally, does this code lead to memory leak?
Not in ARC. In MRC, you would need to add the -autorelease.
The static analyzer would also point out that leak.
There's no reason to not write code as you ask for consideration on… nothing prohibited in the slightest. These objects get released in the same manner that any other object gets released. Your lack of a variable to store the pointer in at the top level isn't important because the Objective C runtime knows about the object.

Why doesn't NSString need memory to be allocated and initialized? [duplicate]

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
NSString allocation and initializing
I was wondering why some objects don't need to be initialized and have memory allocated. I read this: Why do some objects not need to be initialized before use in objective-c? And they said that the method date initialized and allocated memory for today. But if I just wrote NSString *str = #"Hello"; does it still initialized and allocated?
When the compiler sees #"Hello", it sticks a symbol in the .o file that says "hey, dev wants a string with contents "Hello". When the linker links together everything, it unique-ifies all the strings and emits a string table that contains all the strings that the code defined within.
So, in effect, the compiler is "allocating and initializing" the string instances at compile and link time.
They are actually stored in a special format that a particular subclass of the NSString class cluster can encapsulate. When your app is run, the instances of this subclass already exist and are simply mapped into memory.
So, no, not allocated and initialized. But, yes, still objects in every sense of the word. The only caveat is that they ignore retain/release/autorelease and, thus, when you do NSString* foo = #"foo";, technically that should also be retained. But, by convention, no one ever bothers and that's just fine.

Does stringWithFormat create a retain +1 instance?

I'm declaring an ivar of type NSString on a class. To initialize the value of this ivar I use the following code:
NSString *myVar;
-(void)inAnyMethod
{
myVar = [NSString stringWithFormat:#"%#",theValue];
}
Do I have to release this ivar? According to my understanding, it is not my responsibility. But in most cases, strings that I use in this manner cause leaks.
What am I missing?
You do not have to release it, because that is a convenience method that returns an autoreleased object.
The way to know if you are getting something with a retain count of 1 that you will need to release is using the Cocoa naming conventions which say that anything that starts with new, alloc or contains copy in the method name will return a retain 1 object, the others will return autoreleased objects like in this case.
In addition to Oscar Gomez answer, note that when you use class methods (those methods with plus sign that you can find in the documentation and are not included in Oscar Gomez list, e.g. stringWithFormat is one of them), you have not to worry about memory management. If you create your own class method, you should do the same: return an autorelease object.
Regarding your code, it cannot work if you simply assign your ivar to the NSString object (returned from that method). In fact, at some point of your application cycle, the object will be released (it has been put in a pool) and your ivar will not reference any object anymore.
The trick: create a #property with a copy policy or send a copy message like the following:
myVar = [[NSString stringWithFormat:#"%#",theValue] copy];
Copy is normally used when a class has subclasses of mutable type. Otherwise use retain. Once done, you have the possession for that object and you have to remember to release it. If you don't do it you cause a leak.
[myVar release];
P.S. Since Xcode 4.2 there is a new compiler feature called ARC.
Hope it helps.