Do I need to release a constant NSString? - objective-c

I'm reading memory management rules to this point where it said
- (void)printHello {
NSString *string;
string = [[NSString alloc] initWithString:#"Hello"];
NSLog(#"%#", string);
[string release];
}
you have ownership and have to release string, but I'm curious about the #"Hello". #" " is the syntax for creating and NSString, and it's an object. So doesn't that get leaked?

#"…" is a literal instance of NSString. When the compiler sees a literal string, it maps the string into the binary file (e.g. your program) and the string is available as an NSString object when the binary is loaded (e.g. when you run your program). You don’t have to manage the memory occupied by literal strings because they’re an intrinsic part of your binary — they are always available, they never get released, and you don’t have to worry about managing their memory.

Bavarious's answer is correct. For the curious, I can add that this is documented in Apple's “String Programming Guide”, specifically the section “Creating Strings” where it says (emphasis mine):
The simplest way to create a string object in source code is to use the Objective-C #"..." construct:
NSString *temp = #"/tmp/scratch";
Note that, when creating a string constant in this fashion, you should use UTF-8 characters. Such an object is created at compile time and exists throughout your program’s execution. The compiler makes such object constants unique on a per-module basis, and they’re never deallocated.

Related

Lifespan of NSString cStringUsingEncoding return value

I have an NSTextField and get its contents like so
NSString *s = [textField stringValue]
Now I want to convert this NSString to a string that my platform-independent C code can handle. Thus I'm doing:
const char *cstr = [s cStringUsingEncoding:NSISOLatin1StringEncoding];
What I don't understand now is how long this "cstr" pointer stays valid. Apple docs for cStringUsingEncoding say:
The returned C string is guaranteed to be valid only until either the
receiver is freed, or until the current memory is emptied, whichever
occurs first. You should copy the C string or use
getCString:maxLength:encoding: if it needs to store the C string
beyond this time.
Two questions about this:
I suppose the aforementioned "receiver" is the NSString returned by the [textField stringValue]. Since I don't own this NSString how can I tell when this will be freed? Is it safe to assume that this NSString won't be freed before the NSTextField widget will be freed?
What does "until the current memory is emptied" mean precisely? I don't understand this at all.
Of course, I could just go ahead and make a copy but I'd like to understand how long the string pointer returned by cStringUsingEncoding is valid.
I know there are several similar questions here but none could really answer my question since in my case, the owner of the NSString is the NSTextField widget and I don't know when this widget will release the NSString or if it stays valid for the complete lifespan of the widget itself.
I suppose the aforementioned "receiver" is the NSString returned by the [textField stringValue]
yes, in this case the receiver is s
Since I don't own this NSString how can I tell when this will be freed?
you don't. you should retain s by storing it in an instance variable for as long as you need it
Is it safe to assume that this NSString won't be freed before the NSTextField widget will be freed?
no, because you don't know what or how the text field returned s to you
What does "until the current memory is emptied" mean precisely? I don't understand this at all.
good question. also, hard to tell, because you don't own the string or know about its underlying implementation. say it was a mutable string that was mutated and had to reallocate memory...
you can be pretty sure of your safety if you copy s, store the copy in an instance variable and then use the copy to get the C string (or just copy the C string).
Receiver for sure means the string s, and the danger to cstr is clear when s is freed. I think the phrase "or until current memory is emptied" is a documentation bug introduced by ARC. It can be read as "or until an ARC-implied release is executed".
See the doc quoted here in 2010 as evidence. I think the author, probably searching for 'autorelease pool' for places to update the docs, was grasping for a harmless, ARC-compatible synonym for "or until the current autorelease pool is emptied". I think it would have been better to just drop the disjunction.
Anyway, either take control of the NSString, or copy the cstring.

What is the different between NSCFString and NSConstantString?

I declare the object variable as a NSString
But when I use the XCode to look into my object, I saw there are two type of String, it seems that the system automatically transfer to another:
What are the different between them? Are they interchangeable to one and others. Also, what is the condition two change to another?
Thanks.
They're both concrete subclasses of NSString. __NSCFString is one created during runtime via Foundation or Core Foundation, while __NSCFConstantString is either a CFSTR("...") constant or an #"..." constant, created at compile-time.
Their interfaces are private. Treat them both as NSString and you should have no trouble.
As far as I know, NSCFConstantString is an implementation of NSString that keeps the string data in code memory. Compiler creates instances of it when you use #"string" constants. You can use NSCFConstantString anywhere an NSString could be used due to subclass/superclass relationship, but obviously not the other way around.
It appears to be an optimization done by the compiler. I'm guessing that the string that is getting converted to an NSCFConstantString is equal to one of the constants that is cached for performance reasons. Your NSCFString is just a toll-free bridged string that can be an NSString or a CFString. See this article for more information.
One of benefits of transforming NSString to NSCFConstantString is next example:
For example - in method cellForRowAtIndexPath for tableView if you will write
NSString *ident = #"identificator";
NSLog(#"%p", ident);
than it would be the same address for every cell. But with
NSLog(#"%p", &ident) it would be different address for every cell.
NSString ident = #"identificator" is a special case - it is created as
a __NSCFConstantString class so all equal string literals will share
the same memory address to optimize memory usage. &ident will get an
address of a local variable pointing to a NSString and will have
NSString** type.
Reference to source (comments).

Does #"some text" give an autoreleased or retain 1 object back?

Given this code:
// Initialize string
NSString *name = #"Franzi";
#"" macro creates a NSString with given text (here the name Franzi) and a RETAIN COUNT OF 1?
So #"" gives an NSString with have to be released or not? Am I responsible for this object?
Second code example then confuses me, even though I am using it that way:
NSSting *message;
message = [NSString stringWithFormat:#"Hello #%!",name];
//message = [NSString stringWithFormat:#"Hello Girl!"];
So message gets released in next run loop, k. But what is with the NSString given as argument for stringWithFormat?
Does the class object NSString release the NSString #"Hello %#"/#"Hello Girl" given as arguement?
Or does #""-Konstruktor only give back autoreleased NSStrings?
The NSString literal notation #"" gives you compile-time constant strings that reside in their own memory space and have constant addresses.
Contrary to popular belief, the reason why you don't release literal strings is not because they are part of the autorelease pool. They aren't — instead, they spend the entire application's lifetime in that same memory space they're allocated at compile time, and never get deallocated at runtime. They're only removed when the app process dies.
That said, the only time you need to memory-manage constant NSStrings is when you retain or copy them for yourself. In that case, you should release your retained or copied pointers, just like you do any other object.
Another thing: it's the literals themselves that don't need memory management. But if you pass them as arguments to NSString's convenience methods or initializers, like you do with stringWithFormat:, then it's those objects returned by the methods and initializers that follow all memory management rules normally.

How are #"Strings" allocated in memory?

I am curious of the memory allocation for the following code.
NSString *myString = [NSString string];
I know this will create an autoreleased empty string, #""
What happens when I then call
myString = #"Hello world";
Is my reference the same as the autoreleased object NSString provided or did I just allocate a new object that I am responsible for releasing?
When wondering whether you own an object, ask yourself:
Does the method I used to create this object...
begin with new?
begin with alloc?
contain copy?
equal retain?
If you can answer "Yes" to any of those, then you are responsible for invoking release or autorelease on the returned object. (Note that the rules for Core Foundation objects are slightly different. Also note that anything that the documentation explicitly says that contradicts this wins. The documentation always supersedes the guidelines)
In the case of your string, the answers to all your questions are "no", so you are not responsible for the object. Constant strings (of the style #"foo") are hard-coded into the application binary and cannot be deallocated. That, however, is an implementation detail. As long as you follow the memory management rules, you'll be good!

What does assigning a literal string to an NSString with "=" actually do?

What does the following line actually do?
string = #"Some text";
Assuming that "string" is declared thusly in the header:
NSString *string;
What does the "=" actually do here? What does it do to "string"'s reference count? In particular, assuming that for some reason "string" is not otherwise assigned to, does it need to be released?
Thanks!
The assignment is just that. The string pointer is basically a label that points to specific address in memory. Reassignment statement would point that label to another address in memory!
It doesn't change reference counting or do anything beyond that in Objective-C. You need to maintain the reference count yourself, if you are running in a non-garbage-collection environment:
[string release];
string = [#"Some text" retain];
However, string literals don't need to be managed, as they get allocated statically and never get deallocated! So the release and retain methods are just NOOPs (i.e. no operations). You can safely omit them.
What does the following line actually do?
string = #"Some text";
Assuming that "string" is declared thusly in the header:
NSString *string;
What does the "=" actually do here? What does it do to "string"'s reference count?
string is not a string.
string is, in fact, not any other kind of Cocoa object, either.
string is a variable, which you've created to hold an instance of NSString. The assignment operator puts something into a variable*. In your example above, you create a literal string, and put that into the variable.
Since string is a variable, not a Cocoa object, it has no reference count.
Assigning an object somewhere can extend the object's lifetime in garbage-collected code (only on the Mac). See the Memory Management Programming Guide for Cocoa for more details.
*Or a C array. Don't confuse these with Cocoa arrays; they're not interchangeable, and you can't use the assignment operator to put things into a Cocoa collection (not in Objective-C, anyway).
When you use a literal like in this case, it is just syntactic sugar to quickly create an NSString object. Once created, the object behaves just like another other. The difference here is that your string is compiled into the program instead of created dynamically.