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!
Related
Please check the following code:
CFUUIDRef uuid=CFUUIDCreate(kCFAllocatorDefault);
NSString *strUuid=(NSString *)CFUUIDCreateString(kCFAllocatorDefault,uuid);
NSString *lowerUuid=[strUuid lowercaseString];
NSLog(#"strUuid retainCount:%tu",[strUuid retainCount]);
CFRelease(strUuid);
CFRelease(uuid);
NSLog(#"lowerUuid retainCount:%tu",[lowerUuid retainCount]);
NSLog(#"lowerUuid:%#",lowerUuid);
run this code in a non-arc project, the output will be:
strUuid retainCount:1
lowerUuid retainCount:1
lowerUuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
lowercaseString is a property of NSString, its definition is:
#property (readonly, copy) NSString *lowercaseString;
so it's reasonable to infer that if the original NSString object is released, lowercaseString property will be released in NSString's dealloc method.
But why in the code above, lowerUuid is still there even after the original strUuid is released?
First of all, standard disclaimer: Don't look -retainCount. It has many caveats to its use and can't really be trusted for anything useful.
That said: Your inference does not describe what's happening. When you ask strUuid for a -lowercaseString, you're not getting some sort of "child" object. The resulting lowercased string is a completely independent object, with its own internal retain count. (It's possible that the original string does retain its own reference to the lowercased string, but that's not your concern.)
In your code snippet, under standard memory management conventions, what is happening in general terms is that the statement [strUuid lowercaseString] returns an "autoreleased" object. So that even if the original string is released, the string that was returned to you remains valid either: (a) at least until the autorelease pool is cleaned up or (b) after its last actual access, depending on ARC status on the project.
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.
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.
In the following function which one is the best practice?
To send an autoreleased object, and make the caller retain it?
or send an allocated object, and make the caller release it?
- (NSString*) convertDataToString :(NSData*)myData
{
//just an example, method might not exist
NSString *str = [[NSString alloc] initWithData:myData];
return str;
return [str autoRelease];
}
Following up on #Chuck's comment, -convertDataToString must not return an object that the caller must release. That would violate the Three Magic Words. If you do not have "copy," "alloc," or "new" in your name, the caller cannot be expected to release the object. If you have "copy" in your name or start with "new" or "alloc," then the caller must release the object.
Objective-C relies heavily on consistent naming and the names mean things. If you learn the naming, then you won't have any problems.
The memory management rules say your first example is — and this is a direct quote — wrong. It's not even a matter of preference, as some answers here seem to indicate. The caller does not normally own the object you return, so it should be autoreleased.
The specific example from the rules says this:
This is wrong. Following the ownership policy, it would result in a memory leak.
– (NSArray *)sprockets {
NSArray *array = [[NSArray alloc] initWithObjects:mainSprocket,
auxiliarySprocket, nil];
return array;
}
The object’s reference to the new array object is limited to the sprockets method. After the method returns, the object loses its reference to the new object so cannot relinquish ownership. That in itself is not a problem. However, following the naming convention set out earlier, the caller is given no indication that it owns the returned object. The caller would therefore not relinquish ownership of the returned object, leading to a memory leak.
You'd want to return an autoreleased object most of the time.
Unless your method name contains one of the following words [alloc, new, copy], you should return an autoreleased object.
If you create, alloc, or copy an object, you are responsible for releasing it. Based on this, you should return an autoreleased object.
I prefer to return the autorelease. It means that you aren't hunting around trying to find where memory is being freed. Keeping memory allocation and deallocation together makes your life easier. After all, you're coding this, why make it harder on yourself.
Both are acceptable, but you should name your method accordingly : if the caller has the responsibility to deallocate it, you have to make this explicit by having your method name contain "create", "alloc" or "copy", else it should not.
More reading on this at http://developer.apple.com/library/mac/#documentation/cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html%23//apple_ref/doc/uid/20000994-BAJHFBGH
It might be a bit more customary to return an autorelease object, but both are okay.
One thing I'm concerned about is I create two ints, but don't release them. Would it be better to make them NSIntegers?
-(void) flipCoin {
int heads = [headsLabel.text intValue];
int tails = [tailsLabel.text intValue];
if (random() %2 ==1 )
{
heads++;
}
else {
tails++;
}
headsLabel.text = [NSString stringWithFormat:#"%d", heads] ;
tailsLabel.text = [NSString stringWithFormat:#"%d", tails];
}
As sha notes, local variables get allocated in the current stack frame. As soon as the current function call returns, the stack gets "popped", and the memory occupied for the current call is not released so much as abandoned, until it is overwritten by the next call that gets pushed into that part of the stack.
So why do we have to release variables like this:
MyClass *myObject = [[MyClass alloc] init];
Well, you actually don't have to worry about "myObject". It's on the stack, just like your ints, and it will get cleaned up when the current call finishes.
What you have to worry about is the memory that myObject—which is a pointer—points to. It's off somewhere on the heap. Constructing an object involves asking the runtime for some semi-permanent place to put it; that process returns a memory address, which your pointer stores.
alloc and release are Objective-C idioms that largely replace C's malloc() and free() functions, but all of them ultimately are asking the computer to set aside memory on the heap, and all of that memory must ultimately be returned, either through an autorelease pool, a release message, or a free() call.
int is what is known as a primitive type. It is not a pointer to an Objective-C object so you cannot release it. You can't even send a message to it.
NSInteger is also a primitive type in the sense that it is a typedef to a primitive type (long usually). So you can't release that either.
What do you need to release? You need to release any object you obtained by sending new, alloc or a method containing copy. You also need to release objects to which you have sent retain. So all of the local variables in the following must be released:
-(void) foo
{
NSString* aString = [[NSString alloc] init];
NSString* aString2 = [aString copy];
NSString* aString3 = [someOtherString retain];
NSString* aString4 = [#"some string" copy];
}
NB due to implementation details, you would actually get away with not releasing the aString4 but you don't need to worry about it.
No. Your heads and tails variables are local and stored on the stack. This won't cause a leak. Your two NSString assignments near the bottom are created using convenience constructors and will be autoreleased for you.
All default datatypes (int, char, BOOL, etc) are automatically managed for you, and do not (and cannot) be released (for all intents and purposes).
NSIntegers behave likewise, as they are just signed ints (or signed longs on 64-bit machines).
Objects you initialize, however, like NSString or NSArray will usually have to be released (unless they are autoreleased, like the NSStrings at the bottom of your code). If you ever call -alloc and -init on something, you will have to later release it. If you ever doubt whether a method returns an autoreleased object, just read the documentation (it will tell you).
Also, if you want to read up on memory management, there are plenty of wonderful sources that will teach you (Google is a great place to start!), and if you ever think that your code leaks memory, run it through Instruments, and you'll be able to tell...