Objective C, Difference between NSSting with "alloc" and without "alloc" - objective-c

NSString *s1 = #"string1";
// NSString *s2 = [[NSString alloc]stringWithFormat:#"string2"];
NSString *s2 = [[NSString alloc] initWithFormat:#"string2"];
I know this is pretty basic concept but I am not 100% clear with this.
First one doesn't allocate a memory address and send one allocates a memory address...
Also second one increases the reference count of the variable but not the first one...
Even though I understand the concept but don't know the situation when I should use the first one or the second one..
When should I use the first one ? also when should use for the second one?
Thanks in advance..

Carl is is right, but there is some subtlety to keep in mind. Consider this:
NSString *s1 = #"string1";
NSString *s2 = [[NSString alloc] initWithString:#"string1"];
NSString *s3 = [NSString stringWithString:#"string1"];
NSString *s4 = [NSString stringWithFormat:#"string1"];
NSLog(#"ptrs %p %p %p %p", s1, s2, s3, s4);
The output is:
ptrs 0x1000010c0 0x1000010c0 0x1000010c0 0x100108da0
That's right; s1, s2, and s3 are all pointing to the same string instance while s4 ends up being a new instance. This is because NSString detects when a string is being initialized from a constant string and, when perfectly valid to do so, returns the constant string instead of bothering to allocate a new chunk of memory to hold the same thing. The stringWithFormat: case is not so optimized likely because all the potential format string processing makes such an optimization both moot and, likely, unnatural to the implementation.
In other words, do not assume that two strings are the same or different merely by code inspection or by pointer comparison. Use isEqual: or, better yet, isEqualToString:.

You should never use the second one - +stringWithFormat: is a class method. Including your first example, you have basically 3 choices:
NSString *s1 = #"string1";
NSString *s2 = [[NSString alloc] initWithString:#"string2"];
NSString *s3 = [NSString stringWithFormat:#"string3"];
s1 in this case is a pointer to a constant string. s2 and s3 both point to new strings that you've created, but s2 has been retained for you, and s3 has been autoreleased. If you just need a temporary object, the autoreleased object s3 or the constant object s1 are good choices. If you need to keep the string around, you should use s2 (actually now that I think about it s1 will work in this case too - it's not really idiomatic, though).
You can make s1 or s3 equivalent to s2 by sending them a retain message. You could also turn s2 into an equivalent object by sending it an autorelease message.

A string literal like #"string1" (or the #"string2" on the second line) is, as you've noted, not an allocation. The string is actually stored as a constant in your executable's data section, just like any constant you've declared. Strings created this way don't really have a reference count; you can send -retain and -release messages to them and nothing will happen.
Your second line is ill-formed; +stringWithFormat: is actually a class method, and it doesn't really make sense to use +stringWithFormat: without having any format parameters. In general, just use the string literal form if you don't have a specific reason to use another form. There's no need to allocate a new object if there's already the constant one floating around your application.

Don't use any ...WithFormat: method if you're just going to pass it a constant string. No need to parse the format string for the trivial case.

Related

iOS memory management about NSString

Is there any different between
NSString * str = #"123";
and
NSString * str = [[NSString alloc] initWithString:#"123"];
from compiler's aspect?
Theoretically yes; in implementation detail, probably not.
In the first case, the compiler creates a constant string and assigns a pointer to it to the variable str. You do not own the string.
In the second case, the compiler creates a constant string (as before) but this time it is used by the run time as a parameter in initialising another string that you do own (because the second string was created using alloc).
That's the end of the stuff you need to know.
However, there is a lot of optimisation that goes on. Because NSStrings are immutable, you'll find that initWithString: actually just returns the parameter. Normally, it would retain the parameter before returning it to you (because you are expecting to own it) but literal strings have a special retainCount (INT_MAX I think) to stop the run time from ever trying to deallocate them. So in practice, your second line of code produces identical results to the first.
This incidentally, is why it is incorrect top say the string is autoreleased in the first case, because it isn't. It's just a constant string with a special retain count.
But you can and should safely ignore the implementation detail and just remember, you don't own the string in the first case, but you do own it in the second case.
Lots of differences. The most important is that you own the second string so you're responsible for releasing it (as is the case whenever you get an object from the init family of methods).
Another is that the former creates a string literal, and if you make a new string with the same literal, they will be pointers to the same object. If you do this:
NSString * str1 = #"123";
NSString * str2 = [[NSString alloc] initWithString:#"123"];
NSString * str3 = #"123";
Then str1 == str2 is false, but str1 == str3 is true. (Of course, the string content is the same, so isEqual: will return true. Also, while this does make for faster comparison, you probably shouldn't use it because it's an implementation detail and could in theory change in the future).
Yes, in the first case you do not own the string and you are not responsible to release it.
In the second case, instead, you are calling alloc thus you become the owner of the object and you must call release on it when you have done, otherwise it will become a memory leak.
In general, if the method you use to get your object contains "new","alloc","copy" or "mutableCopy" then you are the owner of the object and you are responsible to release it.
Check the memory management rules
Yes. The first is assignment of an NSString, and in the second the alloc (which means you need to release it in some way later) and initWithString: method are getting called.
Yes , first statement creates an autorelease object.
Second one creates an object occupying some memory and you have to release it after using it.
The main important difference about memory (your question title) is:
when you do:
NSString* myString = #"my text";
you are allocating an object of NSConstantString type.
The difference with NSString is:
NSConstantString is statically allocate, while NSString is dynamically allocated.

Pros and Cons of using [NSString stringWithString:#"some string"] versus #"some string"

I want to compare the following simple assignments:
...
#property(nonatomic,retain) UITextField *textField;
...
self.textField.text = #"some string";
self.textField.text = [NSString stringWithString:#"some string"];
self.textField.text = [NSString stringWithFormat:#"some string"];
Where textField is an UITextField and the text property a NSString. Of course all of them work. I know the difference of the last two when using parameters. But lets say we are only interested in this usage.
QUESTIONS:
For doing this kind of assignment, why shouldn't I always use the first one?
Comparing the last two, is there any difference for the compile- and/or runtime of these two? And why should I use stringWithString: at all if not?
Always try to do what feels natural. If you're assigning a constant string then do that, i.e. the first option. #"..." strings are very efficient constants that do not need to be memory managed, so use them if it makes sense.
NSLog(#"%p", #"XX");
NSLog(#"%p", #"XX");
NSLog(#"%p", #"XX");
Results in:
0xa2424
0xa2424
0xa2424
i.e. They are all the same object in memory.
NSLog(#"%p", [NSString stringWithString:#"XX"]);
NSLog(#"%p", #"XX");
NSLog(#"%p", [NSString stringWithString:#"XX"]);
Also results in:
0xa2424
0xa2424
0xa2424
As you can see from this there is no difference between the two objects, thus using -stringWithString: is just an extra message to send. Having said that, the overhead is usually not big enough to make a difference, so it shouldn't be a big deal either way. Personally I'd go with method one as there is no benefit of using method two, it's just extra code.
However,
NSLog(#"%p", [NSString stringWithFormat:#"XX"]);
NSLog(#"%p", [NSString stringWithFormat:#"XX"]);
NSLog(#"%p", [NSString stringWithFormat:#"XX"]);
Results in:
0x7f86730
0xf8479b0
0x8a4cdb0
As you can see, a new string is created each time as the sting you provide is just a format string that is used to process the following substitution variables, as you have none avoid stringWithFormat: unless you need it.
(Obviously all addresses are examples...)
For doing this kind of assignment, why shouldn't I always use the first one?
For that kind of assignment you would always use the first one, and never the last two.
why should I use stringWithString: at all if not?
Your intuition is correct. In most cases -stringWithString: is of dubious value. It's primarily meant for use with NSMutableString, which is a subclass of NSString.
For example:
NSMutableString* myString = [NSMutableString stringWithString:#"Foo"];
[myString appendString:#"Bar"];
You can also use it if you want to convert an NSMutableString to NSString, or otherwise ensure that you're dealing with an NSString instance. For example:
- (void):setMyString:(NSString*)newString
{
[_myString release];
_myString = [[NSString stringWithString:newString] retain];
}
That's one way to ensure that the _myString ivar is pointing to an NSString instance and not an NSMutableString instance. And the newString instance is only copied if necessary.
However, most developers would just use _myString = [newString copy]; in that case.
For doing this kind of assignment, why shouldn't I always use the first one?
You should always use the first one in the situation you describe. The second and third cases potentially copy the constant string, but the text property of UITextField is specified as copying the provided string anyway. There's no sense in making a copy of a constant string just so UITextField's -setText: can copy that copy.
Comparing the last two, is there any difference for the compile-
and/or runtime of these two? And why should I use stringWithString: at
all if not?
My understanding is that -stringWithFormat: will always create a new string, while -stringWithString: might not (probably doesn't) for a constant string. hypercrypt's results above are pretty telling in this respect; if you wanted to explore that more, you might try the same test with a mutable string.
I don't think it matters if you use the first or the second for strings.
I usually use the second one however.
In the case of the second and third, if you have another variable you would like to include in your string then you use the stringWithFormat one. Otherwise, use stringWithString.
int number = 5;
NSString *str = [NSString stringWithFormat:#"Number is: %i", number];
// Str is "Number is: 5"
Situation where you would use stringWithString:
NSString *myName = [NSString stringWithString:#"FN LN"];
// myName is "FN LN"
You would use the latter when you have no other variables to include in the string.
Also, this question has been answered countless times elsewhere.

Using malloc to allocate an array of NSStrings?

Since NSSstring is not defined in length like integer or double, do I run the risk of problems allocating an array of NSStrings for it using malloc?
thanks
ie:
NSString ***nssName;
nssName = (NSString***) malloc(iN * sizeof(NSString*));
the end result with for_loops for the rows is a 2D array, so it is a little easier to work then NSArray(less code).
No problems should arise, allocating an array of NSStrings is like making an array of the pointers to string objects. Pointers are a constant length. I would recommend just using NSArray but it is still fine to use a C array of NSStrings. Note that this may have changed with ARC.
Here is completely acceptable code demonstarting this:
NSString** array = malloc(sizeof(NSString*) * 10); // Array of 10 strings
array[0] = #"Hello World"; // Put on at index 0
NSLog(#"%#", array[0]); // Log string at index 0
Since NSString is an object (and to be more precise: an object cluster) you cannot know its final size in memory, only Objective-C does. So you need to use the Objective-C allocation methods (like [[NSString alloc] init]), you cannot use malloc.
The problem is further that NSString is an object cluster which means you do not get an instance of NSString but a subclass (that you might not even know and should not care about). For example, very often the real class is NSCFString but once you call some of the methods that treat the string like a path you get an instance of NSPathStore2 or whatever). Think of the NSString init methods as being factories (as in Factory Pattern).
After question edit:
What you really want is:
NSString **nssName;
nssName = (NSString**) malloc(iN * sizeof(NSString*));
And then something like:
nssName[0] = #"My string";
nssName[1] = [[NSString alloc] init];
...
This is perfectly fine since you have an array of pointers and the size of pointer is of course known.
But beware of memory management: first, you should make sure the array is filled with NULLs, e.g. with bzero or using calloc:
bzero(nssName, iN * sizeof(NSString*));
Then, before you free the array you need to release each string in the array (and make sure you do not store autoreleased strings; you will need to retain them first).
All in all, you have a lot more pitfalls here. You can go this route but using an NSArray will be easier to handle.
NSStrings can only be dealt with through pointers, so you'd just be making an array of pointers to NSString. Pointers have a defined length, so it's quite possible. However, an NSArray is usually the better option.
You should alloc/init... the NSString*s or use the class's factory methods. If you need an array of them, try NSArray*.
You should not use malloc to allocate data for Objective-C types. Doing this will allocate memory space but not much else. Most importantly the object will not be initialized, and almost as importantly the retain count for the object will not be set. This is just asking for problems. Is there any reason you do not want to use alloc and init?

Usage of NSString and NSMutableString objects in Objective C

I need to use a bunch of string variables throughout my program. I reassign some of them quite often, while others are stuck with the same value during execution.
What's the best practice here?
In the first case, the variables should be NSMutableString and I should cast them to NSString (using the copy method) whenever they need to be arguments of functions that require NSString objects. Is that right?
When I reassign them to other constant values, I shouldn't have to dispose the previous content, right?
As for NSString objects, if I need to assign a new value to them, I guess I should deallocate them, allocate them again, and then assign the new value. Is that correct?
Unless you're actually modifying a string, you shouldn't use NSMutableString. You're reassigning the whole string to a new value, so stay with a regular NSString. Use the autoreleased versions, because that'll be more efficient than alloc/init/release all the time. You could also just reassign your strings to constants if you know what they'll be assigned to.
In the first case, the variables should be NSMutableString and I should cast them to NSString (using the copy method) whenever they need to be arguments of functions that require NSString objects. Is that right?
Well, you could do it that way, but it would be really inefficient. Remember inheritance—an NSMutableString is an NSString, just with some new stuff tacked on. A simple cast will do the trick:
NSString *string = (NSString *)aMutableString;
Even better though, you don't even have to do that. Because of inheritance, you can directly pass in a mutable string wherever a regular string is required, no casting required. That's the beauty of inheritance.
When I reassign them to other constant values, I shouldn't have to dispose the previous content, right
For neither mutable or immutable strings. Old values are simply overwritten in memory—nothing to dispose of there. As far as the memory management goes, it's really not efficient to literally be creating new strings all the time. Just reassign them. You will never need to alloc/init one string more than once, and that single init should be balanced by a single release.
Addendum: When Should You Use Mutable?
A mutable string should be used when you are physically changing the value of the existing string, without completely discarding the old value. Examples might include adding a character to the beginning or the end, or changing a character in the middle. With a mutable string, you can do this "in place"—you'll just modify the existing string. By contrast, an immutable string, once its value is set, cannot change that value. NSString has methods such as stringByAppendingString:, which does add a string to an existing one—but it returns a new string. Behind the scenes, NSString has copied your old string to a new (larger) memory location, added the argument, and returned the new string. That copying is a lot less efficient (relatively speaking, or if you have to do it a lot).
Of course, there's nothing stopping you from physically assigning one string to another. Old values will be overwritten. Most NSStrings, including the #"String Constants", are autoreleased. If you are creating a new string and you decide to alloc/init, you can then assign it to another value without consequence:
myString = anotherString;
myString = myTextField.text;
You can do this with both mutable and immutable strings. The main takeaway is that you should only use mutable when your changing the string itself. But you can change the variable with both mutable and immutable strings without compiler or runtime issues (short of memory management, but most of it is autoreleased anyway).
As for NSString objects, if I need to
assign a new value to them, I guess I
should deallocate them, allocate them
again, and then assign the new value.
Is that correct?
You don't deallocate NSString if you didn't allocated it before, like here:
NSString *string = [NSString stringWithFormat:#"Hello"];
You only need to deallocate it when you call alloc:
NSString *string = [[NSString alloc] initWithString:#"Hello"];
[string release];
The only difference between NSMutableString* and NSString* is that mutable string can be changed.
You don't have to cast anything, since NSMutableString is a subclass of NSString, nor take different memory measures ( so you are right * ).
If you need a modifiable version of a string you just do
NSMutableString* myMutableString = [NSMutableString stringWithString:myString];
You should not 'copy' anything.
Note that if you call :
NSString* myString = myMutableString;
myString is still a mutable String.
So if for any reason (security...) you relly need unmutable strings, you have to call
NSString* myString = [NSString stringWithString:myMutableString];
* you are right, but you could also call [replaceCharactersInRange:withString:] on the mutable string. if there is enough space from previous allocation, then it may be faster, since there is no destruction and new allocation to do.
( Added later : forgot the setString: method )

Char * vs NSString *

I am trying to get rid of some confusion when working with C.
Is using char *name in some sense the same as working with NSString *name in the sense that the pointer still points to the first memory allocation for it?
Ofcourse NSString has a bunch of extras but that isnt what I mean, will working with char *name allow me to work as if it was a NSString *name, so that I could in the future just work with the pointer "name" ?
The answer is no.
char* is meant to point to a simple array of (or single) char data values.
char* myCharPtr = "This is a string.";
//In memory: myCharPtr contains an address, e.g. |0x27648164|
//at address 0x27648164: |T|h|i|s| |i|s| |a| |s|t|r|i|n|g|.|\0|
On the other hand, NSString *name will be a pointer to an object which could have lots of extras, and you can't rely on where the actual character data is stored, or how. It is not encoded as ASCII (Sherm Pendley down below said it's UTF-16), and it could have extra data like the string's length, etc.
NSString* myStringPtr = #"This is an NSString.";
//In memory: myStringPtr contains e.g. |0x27648164|
//at address 0x27648164: |Object data|length|You don't know what else|UTF-16 data|etc.|
You alter and access unknown objects through their exposed methods because you don't know how they are formatted in memory, and thus can't access their data directly. (Or because they encapsulate themselves to hide it from you.)
You can still use the NSString pointer in future if you declare it as NSString *name though. This is what I mean:
NSString *name = #"This is a string.";
NSString *sameName = name; //This is pointing to the same object as name
NSLog(#"%#", sameName); //This prints "This is a string.", and if NSStrings were mutable, changing it would change name as well.
//They point to the same object.
char* and NSString* are two completely different implementations of strings.
NSString can only be used in Objective C (not in plain C), represents immutable strings, is based on Unicode characters and - being an object-oriented class - provides many methods. Furthermore, they are reference counted and always allocated on the heap.
char* is just any array of bytes, whose encoding is not well defined, it's mutable and it isn't object-oriented. char arrays can be allocated on the heap (with malloc) or on the stack. The former requires a call to free, while the latter must never be freed.
Is using char *name in some sense the
same as working with NSString *name in
the sense that the pointer still
points to the first memory allocation
for it?
I think you should regard the NSString* name as a handle to the object rather than a pointer to the object and as such not assume it points to the first memory allocation. I think that would be a better metaphor.
No,
char * is a pointer to an array of characters. NSString is a pointer to an NSString object. I cannot find any documentation of it, but I believe that NSString boxes a char *. Doing name[1] against NSString *name would refer to the 2nd element of an array of NSString objects.
In a sense - a somewhat non-useful sense, to be sure - they are the same, in that both are pointer types that refer to a memory address. That similarity turns out to be not very useful in practice though. To make use of either one, you have to take into account the type of "thing" they point to, and how one uses an array of char and an NSString instance is entirely different. Even for something as simple as assignment, one needs to handle the NSString instance in accordance to Cocoa's memory-management rules, using either -copy or -retain instead of a simple "foo = bar" assignment.