NSString allocation and initializing - objective-c

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).

Related

Difference between Strong and Weak references (Using ARC) Please No Theory..I know the difference theoretically

I have been trying to understand the difference between Strong and Weak references in iOS. What I did to understand is:
//.h File
#property(nonatomic,strong) NSString* myStrongString;
#property(nonatomic,weak) NSString* myWeakString;
//.m File
- (void)viewDidLoad
{
[super viewDidLoad];
[self assignTempString];
// Do any additional setup after loading the view, typically from a nib.
}
-(void)assignTempString{
self.myStrongString = [[NSString alloc] initWithString:#"Varun Mehta"];
}
- (IBAction)printAssignedString:(id)sender {
NSLog(#"Object will have strong reference so it will print my name==%#",self.myStrongString);
}
According to my understanding when I repeat the above step by using myWeakString it should print null. But its still printing my name. Anybody having any idea why its happening.
But when I replace [[NSString alloc] initWithString:#"Varun Mehta"] with [NSString stringWithFormat:#"Varun Mehta"] or [[NSString alloc] initWithFormat:#"Varun Mehta"] result is coming as I have expected.
There are several things to consider here.
A statically declared string is built into your app so it isn't really retained or released, thus a weak reference to #"my string" will always be valid. The compiler is just recognizing [[NSString alloc] initWithString:#"Varun Mehta"] as a static string and removing your alloc/init. However anything that deals with formatting is, by definition, creating a new string and thus the new string obeys the weak referencing rules and is immediately deallocated, nil-ing out the reference.
If you access a weakly retained object that ends up in the autorelease pool it won't actually get deallocated until all your methods return and the run loop goes back into another cycle (and thus drains the autorelease pool), so you can continue to work with the object even though it is "walking dead". This is typically only when interacting with non-ARC code.
If you need practise try this code:
- (void)viewDidLoad
{
[super viewDidLoad];
[self assignTempString];
}
-(void)assignTempString{
#autoreleasepool
{
self.myStrongString = [NSString stringWithFormat:#"%#", #"Strong string"];
self.myWeakString = [NSString stringWithFormat:#"%#", #"Weak string"];
}
}
- (IBAction)printAssignedString:(id)sender {
NSLog(#"Strong ptr content: %#",self.myStrongString);
NSLog(#"Weak ptr content: %#",self.myWeakString);
}
[NSString alloc] will allocate an ARC-managed object and will set its retain count to 1. As long as your view controller is alive, this retain count will be 1, so it will not be deallocated. [NSString stringWithFormat:] returns an autoreleased string which is deallocated after the execution of [self assignTempString].
Two methods initWithString and stringWithFormat suggest exactly what is to expect.
So initWithString expects you to create allocate memory and then initialise it.
While stringWithFormat expects you to just point to the string.
When you do a init with your strong/weak variable it will exist till end of your program.
While when you point;
strong literal will keep a reference and hence will not allow ARC to cleanup the string literal,
weak literal will not keep a reference and hence ARC is free to clean it up immediately after the function call.
Hope it clarifies working for you.
What you are experiencing happens because of how NSString is implemented.
Since NSString objects are immutable the compiler takes a shortcut when you use stringWithString: with a string literal as argument. If the argument of this and other related methods is a string literal the returned value will just point to the string literal. The whole object instantiation is optimized away.
And string literals won't be deallocated. But the weak variable is only nil'd out during dealloc, so if dealloc is never called the weak variables are never set to nil.
This won't happen if you use stringWithFormat:. Even using only string literals as argument will create new string instances.
Why? Most likely because Apple decided that it's not worth the effort to check if stringWithFormat: was used with a string literal that does not have any format specifiers.
That's an implementation detail, don't think too long about this decision. It should not influence the code you write. I would suggest you treat every string that is not a bare literal (i.e. #"Foo" without any NSString methods) as dynamically created NSString (i.e. use isEqualToString: for all your string comparisons)
This logging code will show this reuse behaviour. It'll show the same addresses for all NSString instances, because the compiler has optimized all those calls to a simple #"Foo".
NSLog(#"%p", #"Foo");
NSLog(#"%p", [[NSString alloc] initWithString:#"Foo"]);
NSLog(#"%p", [NSString stringWithString:#"Foo"]);
NSLog(#"%p", [[NSString stringWithString:#"Foo"] copy]);
NSLog(#"%p", [#"Foo" copy]);
In newer versions of Xcode you will even get nice warnings for this code:
using initWithString: with a literal is redundant
using stringWithString: with a literal is redundant

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.

objective-C: simple question about copy/retain NSString

If I set a NSString as property
#property (copy) NSString* name;
I always want to use (copy), so that if its value change, all object with such string still have the old value (as specifiedhere).
However, what happens if my NSString is not a class property, but it is just declared in the code ? Is in that case retained or copied everytime I assign a new value ?
thanks
It depends on how you declare it. You should read the documentation on memory management. Basically the rules are:
NSString *aString = [NSString stringWithString:#"Hello"];
NSString *bString = [NSString stringWithFormat:#"%#", #"Hello"];
In these cases, the string is not copied or retained. It is autoreleased, which means it will be automatically deallocated the next time the autorelease pool drains. You do not have to call the release method on them. (So assigning a new value will not cause it to leak.)
NSString *cString = [[NSString alloc] initWithFormat:#"%#", #"Hello"];
[cString release];
According to Objective C convention, methods that use alloc and have a retain count of one are not autoreleased, so you need to release them explicitly. Assigning a new value without releasing the old one will cause a leak.
You can also explicitly call a "copy" method or a "retain" method on a string. In either case, the new string will have a retain count of 1 and will not be autoreleased, so you will need to call the release method on it before you assign a new value.
NSString *dString = [cString retain];
NSString *eString = [cString copy];
...
[dString release];
[eString release];
If it is a property, and you use self.variableName, this will be taken care of for you (through the getters and setters which are generated with #synthesize). If you do it explicitly, you must make sure to call release on variables that you have called retain or copy on.
Edit: As some commentators below have noted, thinking about management in terms of "ownership" is usually the preferred of describing these ideas, rather than retain count.
If it's not a property and just declared in code, you need to explicitly retain or copy it, ie
NSString myString = [otherString copy];
or
NSString myString = [otherString retain];
Either way you also need to ensure it's released at somepoint.
If you're not using the property's setter, like self.name = #"foo" or [self setName:#"foo"], but rather assign the variable directly, like name = #"foo", it doesn't matter at all how the property is declared.
You have to understand that the property syntax is just a shortcut for writing accessor methods (-name and -setName: in this case). If you're not calling these methods (implicitly by setting the property), it doesn't matter how they work internally (which is what you specify by retain or copy).

When not to alloc and init an NSString

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?
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.
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.
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
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.

confused about NSString *str

I am kind of confused by the behavior of NSString *str..
I assigned it in several ways, sometimes it works, and sometimes it becomes null.
NSString *str = #"/hi/hello"; // this one always works
// this sometimes becomes null after the function ends
NSString *str2 = [str lastPathComponent];
// as above
NSString *str3 = [NSString stringWithString:str2];
NSString *str4 = [NSString initWithString:str3];
I am not quite familiar with the object behavior of Obj-C, is it just like C++?
If so, how can I do assignment safely like
string str = "hi";
string str2 = str;
behaves in C++?
ex: I declare a string in my .h file,
how to assign it safely that it wouldn't become NULL after a function ends?
I know it's a very basic question, but I can't find the answer in NSString reference page.
Really thanks for any help!
The behaviour is not just like C++. Objects are reference-counted. If you want to keep one around, you must place a claim on it.
If you create the object yourself with a method whose name includes the word alloc, new or copy then you have ownership already. This is like a C++ new. (When you have created an object with alloc, you need also to initialise it with some method whose name begins init. But you have to create it first. In C++ both things would be considered parts of the single act of construction.)
Objects you receive from other methods (such as two of the three NSString methods you mention) are only transiently available unless you explicitly claim ownership by calling [object retain]. You only need to do this if you want to keep them around beyond the immediate context. (There isn't really an equivalent to this in C++.)
However you gain ownership, you must relinquish it when you are finished by calling [object release]. This sort of like a C++ delete, except that the object isn't actually destroyed until all ownership claims are released.
Getting to grips with this is really really really important, perhaps the only important thing you need to know to use Objective-C. Read the object ownership documentation carefully and you'll be sorted.
I assume you're not using garbage collection? If this is the case then you need to retain the string.
NSString* str2 = [[str lastPathComponent] retain];
I suggest you do some reading on objective-c memory management.
NSString *str = #"/hi/hello";
This works because it creates a string literal. Answers to this question are worth a read to understand these in Objective-C
What's the difference between a string constant and a string literal?
In all these cases you are creating autoreleased strings. These will be deallocated when you return to the application's runloop.
NSString *str2 = [str lastPathComponent];
NSString *str3 = [NSString stringWithString:str2];
In this last one I assume you meant [[NSString alloc] initWithString:str3]
This creates a string that is retained. But this isn't a good way to create static strings.
You should create static strings in your implementation file like this
static NSString *myConstant = #"constantString"