NSString memory lifecycle - objective-c

Trying to understand memory management in Objective C. Any help will be appreciated.
NSString *myString;
What above line does, does it allocate memory to myString? If so then how many bytes?
If declaration of myString allocate memory to myString object then how compiler or runtime system will know how big string myString object will receive. I mean string could be of any length. So how much memory should be allocated?
myString =[NSString stringWithFormat:#"Testing String"];
What will happened to the memory when object is no longer in use? Will the memory be released or will it be occupied by the content of myString until app is running?

NSString *myString; does not allocate a string. Rather it reserves enough bytes to hold a pointer to a string; the lifetime of that pointer is dependent upon where in code the line is placed (and is not otherwise controllable).
myString =[NSString stringWithFormat:#"Testing String"]; does the allocation*, and the string size is exactly enough to hold the string that results from your format; in this case enough for the characters "Testing String".
When the myString pointer goes out of scope, and assuming there have not been any other copies of the string, and if you're using ARC, the string will be deallocated. If you're not using ARC, you have the responsibility of deallocating it when you're done with it.
Allocation:
Generally speaking, an Objective C allocation will look like pointer = [Class alloc]; and in practice it's more likely to look like pointer = [[Class alloc] init]; (or any of the class's other init* methods). The [NSString stringWithFormat:(NSString *), ...] method is a convenience to lead to (either exactly or in essence) [[NSString alloc] initWithFormat:(NSString *), ...].

Related

Using alloc, init in ARC enabled projects

Actually I am working on a project with ARC enabled. I know using alloc and init is taking ownership of the object. I know, If I create a string like this
NSString *myString = [[NSString alloc]initWithFormat:#"Something"];
then I need to release the myString on myself. What If I am using ARC enabled? I cannot release on myself. So will it create a leak? Or should I don't create object like this?
I can create a string like below code too.
NSString *myString = [NSString stringWithFormat:#"Something"];
But which type I need to use exactly for ARC enabled project ? What will happen if I use first type?
If you use ARC, all the necessary release calls will be added for you when you compile. It will not leak.
The difference between
NSString *myString = [[NSString alloc]initWithFormat:#"Something"];
and
NSString *myString = [NSString stringWithFormat:#"Something"];
is that the first one will automatically released after the last reference to myString in that block, while the second one is an autoreleased instance that will only be released at the end of the run loop. It's not a big difference, but if you're using a lot of objects, try to avoid autoreleased ones to keep memory usage low.
ARC takes care of the memory management, so no you don't need to worry about calling release on your myString variable, ARC will do that for you. Also as a suggestion I would recommend using convenience methods to create your object such as
[NSString stringWithFormat:#"Something"];
It's enough to set the string pointer to nil to release it.
You can also do the same things that you would be able to do without ARC, but with the advantage that if you don't explicitly do anything, the ARC will manage (almost) everything for you.
So to release it you set it to nil, let's see what else you could do:
NSString* str= [[NSString alloc]initWithUTF8String: "Hello"];
// here the retain count of str is 1
__unsafe_unretained NSString* string= str;
// again 1 because string is __unsafe_unretained
void* data= (__bridge_retained void*) string;
// data retains the string, so the retain count is to 2
// This is useful in the case that you have to pass an objective-c object
// through a void pointer.You could also say NSString* data= string;
str=nil;
// Here the retain count of str is 1
NSLog(#"%#",(__bridge NSString*)data);
UPDATE
Here's why sometimes you don't notice that an object is released:
NSString* str= [[NSString alloc]initWithString: #"hey"];
__unsafe_unretained NSString* str2=str;
str=nil;
NSLog(#"%#",str2);
In this case str=[[NSString alloc]initWithString: #"hey"] is equal to str=#"hey", with the difference that str is autoreleased and not released.But the compiler optimizes the code in str=#"hello", so if you are inside an autorelease block you won't have any problem, str2 will be printed correctly.
That's why I used initWithUTF8String, to avoid that compiler optimization.

NSString allocation and initializing

What is the difference between:
NSString *string1 = #"This is string 1.";
and
NSString *string2 = [[NSString alloc]initWithString:#"This is string 2.];
Why am I not allocating and initializing the first string, yet it still works? I thought I was supposed to allocate NSString since it is an object?
In Cocoa Touch,
-(IBAction) clicked: (id)sender{
NSString *titleOfButton = [sender titleForState:UIControlStateNormal];
NSString *newLabelText = [[NSString alloc]initWithFormat:#"%#", titleOfButton];
labelsText.text=newLabelText;
[newLabelText release];
}
Why do I not allocate and initialize for the titleOfButton string? Does the method I call do that for me?
Also, I'm using XCode 4, but I dislike iOS 5, and such, so I do not use ARC if that matters. Please don't say I should, I am just here to find out why this is so. Thanks!
The variable string1 is an NSString string literal. The compiler allocates space for it in your executable file. It is loaded into memory and initialized when your program is run. It lives as long as the app runs. You don't need to retain or release it.
The lifespan of variable string2 is as long as you dictate, up to the point when you release its last reference. You allocate space for it, so you're responsible for cleaning up after it.
The lifespan of variable titleOfButton is the life of the method -clicked:. That's because the method -titleForState: returns an autorelease-d NSString. That string will be released automatically, once you leave the scope of the method.
You don't need to create newLabelText. That step is redundant and messy. Simply set the labelsText.text property to titleOfButton:
labelsText.text = titleOfButton;
Why use properties? Because setting this retain property will increase the reference count of titleOfButton by one (that's why it's called a retain property), and so the string that is pointed to by titleOfButton will live past the end of -clicked:.
Another way to think about the use of retain in this example is that labelsText.text is "taking ownership" of the string pointed to by titleOfButton. That string will now last as long as labelsText lives (unless some other variable also takes ownership of the string).

Explain object variable declaration and assignment

In this snippet:
NSString *testString;
testString = [[NSString alloc] init];
Why, on the second line, do we not have to write *testString = ... in order to access the location where it's actually pointing?
After the first line, what is *testString and what is testString?
The first line you are creating the pointer of NSString type. Pointers in C++ and Objective-C are denoted by the asterisk (*) character when you declare them. The second line you are saying this pointer called "testString" references the memory location of the NSString object that you have allocated in memory.
All objects are referred to by pointers. The first line
NSString * testString;
declares the instance variable. If your variable type is an object (aside from type id), you need the *
from then on the reference to testString is pointer
If you create 2 strings. 2 physical objects are created (in memory)
NSString * testString = [[NSString alloc] init];
NSString * testString2 = [[NSString alloc] init];
//setting testString to testString2 will lose the pointer to testString for good
testString = testString2; //<--bad if you still care about testString (and leaks the memory too)
I recommend checking out Apple's guide on Objective-C. Specifically this section
http://developer.apple.com/library/mac/#documentation/cocoa/conceptual/objectivec/Chapters/ocObjectsClasses.html#//apple_ref/doc/uid/TP30001163-CH11-SW1
Why, on the second line, do we not have to write *testString = ... in order to access the location where it's actually pointing?
The init method returns a generic pointer to an object -- its return type is id. testString is a pointer to an NSString, which is an object, so you are assigning a pointer to another pointer. Dereferencing the assigned-to pointer would be a type mismatch.
A variable name is a place (a label for a memory address) in which to put something. The type of the variable is the kind of thing that you can put there. In the case of a pointer, the kind of thing that you put in it is also a memory address. In order to get that address, you dereference the pointer. The kind of thing that you can put at that address is different from the kind that you put in the pointer itself.
After the first line, what is *testString and what is testString?
After the first line, *testString, or the thing at which testString points, is garbage (actually undefined). testString is a pointer (4 or 8 bytes depending on your system) to a address in memory, and it is also undefined.
After the second line, *testString is an NSString object. testString is still a pointer to an address, where there is a valid NSString object.
That's simply because we affect the pointer.
[[NSString alloc] init] returns a pointer to an NSString.
In Cocoa every object is dynamically allocated (as in malloc in C) and every NSObject is manipulated thru its pointer/address (in such a point that many ObjC programmer don't even know that they are manipulating pointers and not objects)

Memory Management Questions

I have been programming in Objective-C for a couple weeks now, and I think its time that I think more about my memory management and so I have a couple scenarios I would like clarification on.
NSString *myString = #"Hello, World";
If I were to on the next line do
NSString *anotherString = myString;
Is it getting copied? or is another string just a pointer to myString? if it's just a pointer how would I make anotherString a copy of myString that has its own memory?
What if I were to
[anotherString release];
What actually gets released, just anotherString, or does myString go away too?
Then if I were to do
anotherString = nil;
Does that actually free up memory and for use or does it still have the space allocated with empty memory? Obviously the pointer can still be used. What does it do to myString?
This will really help me become better at managing the memory properly, instead of just [object release]; randomly and causing crashes.
Thank you VERY MUCH in advance to whoever replies.
When you do:
NSString *myString = #"Hello, World";
NSString *anotherString = myString;
...you're creating a single NSString instance, and two pointers to it. So to answer your questions, no it is not being copied. Yes, anotherString is just a pointer, and so is myString, the actual NSString instance is off in memory-land, at the address that both pointers are now pointing to.
To make a copy of the string, you would do:
NSString *anotherString = [myString copy];
When you do:
[anotherString release];
The NSString instance that anotherString points to is released. Nothing happens to anotherString itself. It continues to point to your now-invalidated object instance. If myString was pointing to the same instance, then yes, this causes myString to "go away" as well.
And if you do:
anotherString = nil;
...then you've caused a memory leak, because you reassigned the pointer without releasing the thing it was pointing at. Except not in this case because #"Hello, World" is a literal value that is loaded onto the stack and is not retained by your code.
In any case, setting anotherString to nil does nothing to your string, it just changes what anotherString points to. Your actual NSString instance is still off in memory-land, completely unaware that you just threw away your reference to it (possible exception: reference counted/garbage collected environments).
And yes, calling [object release] randomly will cause crashes. As a general rule you should only call release on something if:
You called alloc and init... on it.
You called retain on it.
You obtained the object as a result of calling copy on some other object.
Note that these stack, so if you alloc something, retain it, and then copy it, you need to have 3 calls to release, two for the object that you alloc'ed, and one for the copy.
As a side note, you may find it clearer to write your object declarations like:
NSString* myString = #"Hello, World";
NSString* anotherString = myString;
...which makes it more obvious that what you are declaring are pointers to NSString's and not NSString's themselves. Personally I think your original syntax, while commonly used, is also backwards.
This string:
NSString *myString = #"Hello, World";
is created on the stack. It's loaded into memory when the app starts. You don't own the memory backing the object, and therefore shouldn't release it.
If you want to copy a string to the heap (where you can manage the memory), you simply do this:
NSString *anotherString = [myString copy];
Then you're responsible for releasing that object when you're done with it.
[anotherString release];
Setting a pointer to nil just clears the pointer, not the object it's pointing to. It's still in memory.
NSString *anotherString = myString;
--- This is just a pointer assignment
--- You can copy myString using [myString copy]
[anotherString release];
--- You are releasing the owner ship of the anotherString (please read about retain count concept)
anotherString = nil;
--- you are just assigning the pointer to nothing.
I suggest Please read more about memory management apple documents ...

NSString - stringWithFormat vs stringWithString

I have a global NSString variable declared in a .m file. When I use the stringWithFormat to give it a string value anywhere within the .m file, that value does not persist in between function calls. However when I do the same using stringWithString, the value persists throughout the implementation and any functions calls thus giving it a true global behavior. Rather to put it differently, how does the memory management differ internally for stringWithFormat vs stringWithString?
Why does the value persist for stringWithString while throwing a "message sent to deallocated instance" (on subsequent use of the NSString say in a NSLog statement in another function which comes after a function that gave the NSString a value using stringWithFormat) when using stringWithFormat? No such issues when I replace the same with stringWithString.
Thanks!
EDIT: I forgot to mention that YES it worked in case of stringWithFormat when I did a manual retain afterward. The value persisted. Hence the question.
It sounds like you aren't retaining the string and because of this when you try to access it later on it has been deallocated. If you aren't familiar with memory management, take a look at the Memory Management Programming Guide from Apple.
The reason -stringWithString: doesn't break is likely because the compiler is doing some optimisation with string literals; It looks through the program and stores just one reference to identical strings that are defined. Because of this your pointer will remain valid throughout the lifetime of the app.
You should not rely on this. You cannot guarantee that all compilers will do this optimisation. Retain the variable when you make it and release it when you stop needing it.
the compiler is smart, and instead of creating dozens of different NSString instances that all hold the same value he creates one instance that can't be released and all the other instances just point to the NSString that is hardcoded in your program.
And because the hardcoded NSString gets never deallocated you can use it even after the autorelease pool would have deallocated it.
This just covers your wrong memory management. And you should definitely not rely on this behaviour.
Edit. there is not much more to say. The NSString that you've created with stringWithString:literal will simply point to the location of literal in memory.
A little example:
NSString *string = #"Foo";
NSLog(#"%# - %p", string, string);
NSString *string2 = string;
NSLog(#"%# - %p", string2, string2);
NSString *string3 = [string copy];
NSLog(#"%# - %p", string3, string3);
NSString *string4 = [string retain];
NSLog(#"%# - %p", string4, string4);
NSString *string5 = [NSString stringWithString:string];
NSLog(#"%# - %p", string5, string5);
NSString *string6 = [[NSString alloc] initWithString:string];
NSLog(#"%# - %p", string6, string6);
you will see they all point to the same address.
2011-02-22 13:24:41.202 xxx[40783:207] Foo - 0x74120
2011-02-22 13:24:41.204 xxx[40783:207] Foo - 0x74120
2011-02-22 13:24:41.204 xxx[40783:207] Foo - 0x74120
2011-02-22 13:24:41.206 xxx[40783:207] Foo - 0x74120
2011-02-22 13:24:41.206 xxx[40783:207] Foo - 0x74120
2011-02-22 13:24:41.207 xxx[40783:207] Foo - 0x74120
And all of them will never get deallocated. So you could access string5 from some other method in your code and it would still point to the address 295740, and the NSString "Foo" would still be there.
But a NSString object that does not point to a string literal would be deallocated at this time, and you would get a bad access exception.
You are violating the memory management rules but you will never notice it if you only use string literals. Until the behaviour of the compiler changes.
So do it right, learn proper memory management and don't rely on internals. Retain all your autoreleased objects if you need them later. Even if they point to string literals