Understanding array pointer - objective-c

I'm new to Objective-C and need help with the concept of pointers. I've written this code:
//myArray is of type NSMutableArray
NSString *objectFromArray = [myArray objectAtIndex:2];
[objectFromArray uppercaseString];
I assumed that this would change the string at myArray[2] since I got the actual pointer to it. Shouldn't any changes to the dereferenced pointer mean that the object in that location changes? Or does this have something to do with 'string immutability'? Either way, when I use NSLog and iterate through myArray, all the strings are still lowercase.

Shouldn't any changes to the dereferenced pointer mean that the object in that location changes?
Yes, they would. But if you read the documentation for uppercaseString, you see that it does not modify the string in place. Rather, it returns a new uppercase version of the original string. All methods on NSString work like that.
You would need an instance of NSMutableString to be able to modify its contents in place. But NSMutableString does not have a corresponding uppercase method, so you would have to write it yourself (as a category on NSMutableString).

of course!! no string in the array will be converted to uppercase as the statement [objectFromArray uppercaseString]; would have returned the uppercase string which was not collected in any object though. "uppercaseString" does not modify the string object itself with which is is called...!!

Related

Is there risk in assigning the output of stringByAppendingString to the same instance?

Is there risk in assigning the output of -[NSString stringByAppendingString] to the same instance? I remember running into issue with this but don't recall the exact situation.
string = [string stringByAppendString:#"more string"];
Before your line executes, string is a pointer to one NSString instance. Afterward, string points to a different instance. You haven't changed the original, you just don't have a pointer to it anymore.
If you're using ARC (the default), or the original string was autoreleased or is a string literal constant, there's no further cleanup to worry about.

objective-c strings: why don't you need a setter/getter?

I'm just beginning, and I'm a little hung up on this. I may have a fundamental misunderstanding with which you can kindly help me out.
Why is it that you can assign a string value to an NSString* (and, I'm sure, many other object types) directly? E.g.,
NSString* s = #"Hello, world!";
whereas the following code, I believe, would assign to s2 s1's pointer value (and therefore only incidentally provide s2 with a string value)?
NSString* s1 = #"Hello, world!";
NSString* s2 = s1;
For many objects, don't you have to indicate a property, a.k.a. instance variable, to which you want to assign a value (i.e., use a setter method)? Shouldn't the object itself accept assignments only of pointer values? Or do classes such as NSString automatically reinterpret code such as the first example above to assign the indicated string to an implied instance variable using an implied setter?
Why is it that you can assign a string value to an NSString* (and, I'm
sure, many other object types) directly?
Though it may look like it, you are not assigning the value of the string 'directly' to the instance variable. You are actually assigning the address of the string value to your instance variable. Now, the real question is what is going on behind the scenes when you have an expression of the type:
NSString * str = #"Hello World";
This expression represents the creation of a string literal. In C (and Objective-C which is a strict superset of C), string literals get special handling. Specifically, the following happens:
When your code is compiled the string "Hello World" will be created in the data section of
the program.
When the program is executing, an instance variable 'str' will be allocated on the heap.
The 'str' instance variable will be pointed at the static memory location where the actual string "Hello World" is stored.
The main difference between your first and second examples is that in the second example the memory for the string variable is dynamically allocated on the heap, at runtime. Note that in both cases the variable 'str' is just a pointer allocated dynamically.
More or less the latter. String literals like #"Hello World!" are treated as a special case in Objective-C: strings declared with that syntax are statically allocated, instantiated and cached at compile time to improve performance. From the programmer's perspective, it's no different from calling [NSString stringWithString:#"Hello World!"] or a constructor that takes a C-string -- you should just think of it as syntactic sugar.
FWIW, Objective-C has recently begun extending the # prefix to allow declaring dictionary and array literals as well, e.g.: #{ #"key" : #"value" } or #[ obj1, obj2, obj3 ].
This is a function of the compiler and not a language construct. The compiler in this case recognizes a string literal and inserts some code to produce the intended result.
#"" is essentially shorthand for NSString's +stringWithUTF8String method.
take from here:
What does the # symbol represent in objective-c?
NSString *s1 = #"Hello, world!";
is essentially equivalent to
NSString *s1 = [NSString stringWithUTF8String:"Hello, world!"];
The former allocates a new NSString object statically (instead of on the heap at runtime, as the latter would do).
It's important to note that these are just pointers. When you do NSString *s2 = s1, both s1 and s2 refer to the same object.

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.

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 )

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.