stringByAppendingString on same object - objective-c

i want to ask a question on NSString, the question is if
NSString str = #"Hello";
str = [str stringByAppendingString:#"World"];
if we NSLog the str we would get an output - HelloWorld!
So my question is if str is NSString class variable an its an static one (which can not be changed once it is defined) then how can we able to change it, (Note that I have used same NSString object str).

You haven't declared the string as static, but NSString is immutable. You are creating a new string and replacing str. Many Obj-C classes have a mutable type, so if you intended to modify your string as in this example, you might want something more like:
NSMutableString *str = [NSMutableString stringWithString:#"Hello"];
[str appendString:#" World"];
Note, #"Hello" is a NSString, so attempting to initialize a NSMutableString using that syntax would result in an error.

Actually, static variables can be changed once they are defined. Static variables are simply maintained throughout all function/instance calls. You can find a more detailed explanation here static variables in Objective-C - what do they do?. So the result would be the same. If the variable were defined as const (which cannot be changed) then you would get a compiler error. Generally speaking, the best way to figure these types of things out is to just try them on your own. If it's just a matter of writing a couple lines of code, or changing a keyword, what does it hurt?

Related

What is the correct way to change a string value in Objective C?

Changing a mutable strings value in many languages is very easy:
myString = "foo"
myString = "bar"
However, while learning Objective C it seems like you have to really, really jump through hoops to change an existing string's value (This is often done with switch or if cases):
NSMutableString *myString;
myString = [NSMutableString stringWithString:#"foo"];
myString = [NSMutableString stringWithString:#"bar"];
Is there an better way to change a string's value?
myString = #"foo"
myString = #"bar"
is fine in obj-c too. Don't confuse changing object value (for which you need NSMutableString) and variable value.
EDIT. Well, maybe you really need to change existing object value, but it's unclear from your question. You don't usually need to mutate existing object for switches.
Objective-C doesn't force you to jump through any extra hoops relative to most languages. It's probably simply less clear what you're doing in other languages perhaps, because for the most part, it's the same.
For starters, Objective-C doesn't allow objects on the stack--only on the heap. This is true for all objects and there's nothing special about strings here. Other languages such as C++ allow objects on the stack.
When we create objects on the heap, our variable is merely a pointer to that object, so when we create an object we have to allocate memory for it.
When we assign a string object via the = operator, we've change the memory location our variable points too.
You can create strings as simply as this:
NSString *fooString = #"foo";
NSString *barString = #"bar";
Which really isn't any more complex then any language I've seen. It's just an extra #, how is this complicated?
CHANGING the value of a string, however, isn't so simple. NSString is immutable, so to change it's value, we have to create a new object on the heap, and point to that. We haven't changed the value, we've created a new object and pointed at that.
With NSMutableString however, there are a range of available methods for changing the actual value at the memory location we point to.
In your example
NSMutableString *myString;
myString = [NSMutableString stringWithString:#"foo"];
myString = [NSMutableString stringWithString:#"bar"];
the first two lines can be grouped together and the third can simply reduce to changing the string property of the mutable string, like this
NSMutableString *myString = [NSMutableString stringWithString:#"foo"];
myString.string = #"bar";
Anyway, mutable strings actually make sense only when you need to pass a reference away and allow it to be changed.
If you simply need to change the value of a NSString * pointer over time, just do
NSString *myString = #"foo";
myString = #"bar";
myString = #"baz";
and be done with it.
It depends on whether you insist on having a string where you can change the bytes inside it or only want to replace it entirely. Replacement of the whole thing doesn't need 'mutable' but if you'd like to replace it and be able to modify the bytes, then you want something like:
NSMutableArray *mstr = [#"foo" mutableCopy];
mstr = [#"bar" mutableCopy];

Best way to Declare & Initialize String Variable in Objective C

I am new to Objective C. we can create String Object by one of these. can anybody tell difference & which is best,simplest way to doing this?
NSString *simpleString = #"This is a simple string";
NSString *anotherString = [NSString stringWithString:#"This is another simple string"];
NSString *oneMorestring = [[NSString alloc] initWithString:#"One more!"];
NSMutableString *mutableOne = [NSMutableString stringWithString:#"Mutable String"];
NSMutableString *anotherMutableOne =[[NSMutableString alloc] initWithString:#"A retained one"];
NSMutableString *thirdMutableOne =[NSMutableString stringWithString:simpleString];
The First method is the simplest and best method for creating string instance if the string is constant. The first method is also prefer as it follow Modern Objectice-C Language.
The Main deference between NSString and NSMutableString is that NSString object is constant. and we can't change or update its value. But NSMutableString has property to change or updates its value.
It really depends on what you want to do.
For simply creating a string from a constant, your first example is best.
stringWithString pretty much just creates a copy of a string, so I don't use it much.
You might want to check out stringWithFormat and stringByAppendingString. Those are two that I use most often.
If you enable ARC, then you don't need to worry about retaining strings. Alloc/init or class factory methods are essentially equivalent under ARC, so use whichever you like best.
There is nothing a best way... It is upto our requirement. However most of the time we opt for manual allocated and initized version of NSString or NSMutableString.
First 3 are Constant String, next three are String which you can manipulate.
Line number 1: is simply a const string.
Line number 2: You are copying a const string you anotherString.
Line number 3: You are manually allocating and initializing it. Its upto you or ARC(compiler) to release it.
Similarly with rest Mutable versions.

Why are these two NSString pointers the same?

When I alloc and init two NSString variables and compare their pointers, they are the same. Here's a snippet that shows this:
NSString *s1 = [[NSString alloc] initWithString:#"hello world"];
NSString *s2 = [[NSString alloc] initWithString:#"hello world"];
if (s1 == s2) {
NSLog(#"==");
}else {
NSLog(#"!=");
}
Why are s1 and s2 the same?
There are three things going on here:
Firstly, the two identical string literals you're passing in to initWithString: will have the same address to start. This is an obvious optimization for constant data.
Secondly, when you nest alloc and init with strings, the runtime performs an optimization, the alloc call essentially becomes a no-op. This is done using the NSPlaceholderString class. This means the pointer you get back here will be coming from initWithString:, not from alloc.
Thirdly, under the hood, initWithString: is calling CFStringCreateCopy, which as you may find, has the following behavior: Since this routine is for creating immutable strings, it has an optimization. It simply calls CFRetain() and returns the same object that was passed in.
Thanks for the very interesting question. I had fun figuring it out.
#"hello world" strings are of class NSConstantString.if you use #"hello world" in two places, they will be referencing the very same object.
From documentation.
The simplest way to create a string object in source code is to use
the Objective-C #"..." construct:
NSString *temp = #"/tmp/scratch"; Note that, when creating a string
constant in this fashion, you should use UTF-8 characters. Such an
object is created at compile time and exists throughout your program’s
execution. The compiler makes such object constants unique on a
per-module basis, and they’re never deallocated, though you can retain
and release them as you do any other object. You can also send
messages directly to a string constant as you do any other string:
BOOL same = [#"comparison" isEqualToString:myString];

Issue comparing NSString literal and constant

I have an NSString, firstWord, that has the value of "First". It was defined like this:
NSString *firstWord = [[NSString alloc] init];
firstWord = [textView text];
However, when I try to check its value, like so:
if (firstWord == #"First"){}
The comparison does not return true, or YES I guess in Objective-C. I know that it does have the same value as a string. So, from this I am pretty sure that the issue is that I am comparing pointers, which are not the same here, even though the strings themselves do have the same value. So how can I directly compare the strings themselves? Or maybe more efficiently, make sure the two string objects do have the same pointer, so I don't have to the do the relatively costly string comparison?
So how can I directly compare the strings themselves?
String comparison in Cocoa is done with isEqualToString:.
Or maybe more efficiently, make sure the two string objects do have the same pointer,
This isn't possible. One is a string literal, stored in the DATA section of your app's binary; the other is on your app's heap. In certain circumstances (creating a string using initWithString:#"literal string") you'll end up with the same address, but you shouldn't rely on that.
As an aside, you don't need to -- in fact, shouldn't, because you're creating a leak -- allocate a string before assigning the text view's text to the pointer.
There are actually two errors.
Your actual question:
if (firstWord == #"First"){}
needs to be
if ([firstword compare:#"first"]==NSOrderedSame) ...
Only works if firstword isn't nil.
In addition:
NSString *firstWord = [[NSString alloc] init];
firstWord = [textView text];
This looses memory, since you are not "copying" the textview into the string (which wouldn't be possible anyway since it's not mutable), you are simply assigning another string object to the pointer. So the empty string that you've allocated is lost.
Just do
NSString *firstWord;
firstWord = [textView text];
EDIT: making sure the strings have the same pointers would be even more costly, since you would have to keep a table of string objects and lookup every string there so you can either replace your pointer with the "unique" one or add the new string to the table...
Start to learn Objective-C from Swift. Here is what I do to give different layout code per deviceModel type.
#property (nonatomic, strong) NSString *deviceModel;
NSString *iPhoneSE = #"iPhone8,4";
if ([self.deviceModel isEqualToString:iPhoneSE]) { // iPhone SE
// layout code
}

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"