What does assigning a literal string to an NSString with "=" actually do? - objective-c

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.

Related

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.

How to access a property/variable using a String holding its name

If I had two variables in Objective C like this where one holds the name of the other as a string
NSInteger result = 4;
NSString * theName = #"result";
How would I best access the first variable using the string instead of a reference to the variable? For instance if I had a lot of variables and would generate the name of the one I need by code I'd need a way to get to the variable using that string.
Though not directly answering your question, it's possible to access properties (or ivars) of an object by
[object setValue:#"value" forKey:theName]
Similarly, the getter is [object valueForKey:theName] (thanks kevboh!)
That's not possible in objective-c. Variable names cannot be synthesised by name. The variable name itself doesn't mean anything when running your code, the compiler converts it into a memory address. The name is just a way for the programmer to make writing and reading code easier.
Depends on your exact situation but you probably should be using an NSArray or NSDictionary.

Understanding array pointer

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

Assigning object pointers

Is this pointer assignment correct?
customclass.somearray = &*otherarray;
where somearray and otherarray are NSArray objects.
If not, how do I solve my problem:
I want to share this otherarray object with customclass.somearray. And I want all changes
made to customclass.somearray to be made to the original otherarray too.
Doing it this way, it works. I just want to ask, is it correct?
Your two variables are pointers of the same type, so just assign one to the other:
customclass.somearray = otherarray;
The way you have written this is unnecessary. Using the dereference operator * essentially gives you the "contents" of the pointer. The address-of operator & correspondingly gives you the address of whatever you apply it to. Your pointer otherarray contains an address. If you dereference that address and then take the address of that, you end up right back where you started.
Be aware that the left side of this assignment is a property access (assuming that customclass is also an object and not just a struct). This means that the compiler will change your expression into:
[customclass setSomearray:&*otherarray];
// And my version will be changed into:
[customclass setSomearray:otherarray];
That is, it becomes a method call rather than a simple assignment. This does not affect the syntax you should use, however.
When working in Objective-C, you never deal with objects directly, but always refer to them via pointers. Always. In C++, you can declare an actual object on the stack, for example, but you never do that in Objective-C. So, if you have:
NSArray *otherArray = [NSArray arrayWithObjects:#"foo", #"bar", nil];
then otherArray is a pointer to an instance of NSArray. Likewise, your somearray property will be of type NSArray*, so the types will match and you can just assign one to the other:
customclass.somearray = otherarray;
Hope that helps.

What's the difference between a string constant and a string literal?

I'm learning objective-C and Cocoa and have come across this statement:
The Cocoa frameworks expect that global string constants rather than string literals are used for dictionary keys, notification and exception names, and some method parameters that take strings.
I've only worked in higher level languages so have never had to consider the details of strings that much. What's the difference between a string constant and string literal?
In Objective-C, the syntax #"foo" is an immutable, literal instance of NSString. It does not make a constant string from a string literal as Mike assume.
Objective-C compilers typically do intern literal strings within compilation units — that is, they coalesce multiple uses of the same literal string — and it's possible for the linker to do additional interning across the compilation units that are directly linked into a single binary. (Since Cocoa distinguishes between mutable and immutable strings, and literal strings are always also immutable, this can be straightforward and safe.)
Constant strings on the other hand are typically declared and defined using syntax like this:
// MyExample.h - declaration, other code references this
extern NSString * const MyExampleNotification;
// MyExample.m - definition, compiled for other code to reference
NSString * const MyExampleNotification = #"MyExampleNotification";
The point of the syntactic exercise here is that you can make uses of the string efficient by ensuring that there's only one instance of that string in use even across multiple frameworks (shared libraries) in the same address space. (The placement of the const keyword matters; it guarantees that the pointer itself is guaranteed to be constant.)
While burning memory isn't as big a deal as it may have been in the days of 25MHz 68030 workstations with 8MB of RAM, comparing strings for equality can take time. Ensuring that most of the time strings that are equal will also be pointer-equal helps.
Say, for example, you want to subscribe to notifications from an object by name. If you use non-constant strings for the names, the NSNotificationCenter posting the notification could wind up doing a lot of byte-by-byte string comparisons when determining who is interested in it. If most of these comparisons are short-circuited because the strings being compared have the same pointer, that can be a big win.
Some definitions
A literal is a value, which is immutable by definition. eg: 10
A constant is a read-only variable or pointer. eg: const int age = 10;
A string literal is a expression like #"". The compiler will replace this with an instance of NSString.
A string constant is a read-only pointer to NSString. eg: NSString *const name = #"John";
Some comments on the last line:
That's a constant pointer, not a constant object1. objc_sendMsg2 doesn't care if you qualify the object with const. If you want an immutable object, you have to code that immutability inside the object3.
All #"" expressions are indeed immutable. They are replaced4 at compile time with instances of NSConstantString, which is a specialized subclass of NSString with a fixed memory layout5. This also explains why NSString is the only object that can be initialized at compile time6.
A constant string would be const NSString* name = #"John"; which is equivalent to NSString const* name= #"John";. Here, both syntax and programmer intention are wrong: const <object> is ignored, and the NSString instance (NSConstantString) was already immutable.
1 The keyword const applies applies to whatever is immediately to its left. If there is nothing to its left, it applies to whatever is immediately to its right.
2 This is the function that the runtime uses to send all messages in Objective-C, and therefore what you can use to change the state of an object.
3 Example: in const NSMutableArray *array = [NSMutableArray new]; [array removeAllObjects]; const doesn't prevent the last statement.
4 The LLVM code that rewrites the expression is RewriteModernObjC::RewriteObjCStringLiteral in RewriteModernObjC.cpp.
5 To see the NSConstantString definition, cmd+click it in Xcode.
6 Creating compile time constants for other classes would be easy but it would require the compiler to use a specialized subclass. This would break compatibility with older Objective-C versions.
Back to your quote
The Cocoa frameworks expect that global string constants rather than
string literals are used for dictionary keys, notification and
exception names, and some method parameters that take strings. You
should always prefer string constants over string literals when you
have a choice. By using string constants, you enlist the help of the
compiler to check your spelling and thus avoid runtime errors.
It says that literals are error prone. But it doesn't say that they are also slower. Compare:
// string literal
[dic objectForKey:#"a"];
// string constant
NSString *const a = #"a";
[dic objectForKey:a];
In the second case I'm using keys with const pointers, so instead [a isEqualToString:b], I can do (a==b). The implementation of isEqualToString: compares the hash and then runs the C function strcmp, so it is slower than comparing the pointers directly. Which is why constant strings are better: they are faster to compare and less prone to errors.
If you also want your constant string to be global, do it like this:
// header
extern NSString *const name;
// implementation
NSString *const name = #"john";
Let's use C++, since my Objective C is totally non-existent.
If you stash a string into a constant variable:
const std::string mystring = "my string";
Now when you call methods, you use my_string, you're using a string constant:
someMethod(mystring);
Or, you can call those methods with the string literal directly:
someMethod("my string");
The reason, presumably, that they encourage you to use string constants is because Objective C doesn't do "interning"; that is, when you use the same string literal in several places, it's actually a different pointer pointing to a separate copy of the string.
For dictionary keys, this makes a huge difference, because if I can see the two pointers are pointing to the same thing, that's much cheaper than having to do a whole string comparison to make sure the strings have equal value.
Edit: Mike, in C# strings are immutable, and literal strings with identical values all end pointing at the same string value. I imagine that's true for other languages as well that have immutable strings. In Ruby, which has mutable strings, they offer a new data-type: symbols ("foo" vs. :foo, where the former is a mutable string, and the latter is an immutable identifier often used for Hash keys).