What is the correct way to change a string value in Objective C? - 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];

Related

stringByAppendingString on same object

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?

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.

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"

In Obj-C How to update an existing NSString variable with a new formatted string?

How do i update an existing NSString variable with a new formatted string?
for example i have a variable like this:
String1 = [NSString new];
I want this string object to be updated from time to time with new formatted contents using the standard printf format.
I can initialise a new NSString using the initWithFormat: message but this is unavailable to already instantiated objects.
Any ideas? I'm thinking i can destroy the NSString each time and re-initialise a new one but is this the correct solution each time i need to update it?
Two options:
Create a new string every time with [[NSString alloc] initWithFormat:#"whatever"] and assign it to the variable. (Make sure you follow the memory management rules, which includes making sure the string's previous value is released. Of course, you'll need to follow those rules no matter how you tackle this problem.)
Create an NSMutableString and update the string with the mutating methods (appendFormat:, setString:, deleteCharactersInRange:, etc.). In this case, you're not just updating the variable, but the string itself.
Personally, I would use method 1, creating a new NSString every time. That way I don't have to fiddle with mutation and can just create a string with the precise value I want.
Strings in Cocoa are immutable objects.
This means that you won't change the same string but you will just free the old one and allocate a new NString with your updated content.
Of course this is not a problem since you will have a NSString* reference that will point to the last updated string.
NSString myString = [NSString stringWithFormat:...];
// do whatever
myString = [NSString stringWithFormat:..]
There is an NSMutableString which can be modified after the initialization. You can add a formatted string using appendStringWithFormat:. But if you want to replace the entire string, just create another. It doesn't cost much time and resources.
It depends on the taste, but I am against re-using a variable as Jack suggested. It often just confuses me, I prefer to create a new variable name whenever I create a new string, as in
NSString* myString = [NSString stringWithFormat:...];
// do whatever
NSString*myString2 = [NSString stringWithFormat:...];
Another thing is that new is not widely-used in Objective-C world. If you use that because it sounds familiar from your C++ background etc., consider using [[Class alloc] initWith...] instead.
The simplest thing to do is just always use "factory" methods that give you an autoreleased immutable object. In fact, you basically do that whenever you create an NSString that holds some static text.
For example:
NSString *myString = #"myString";
myString = [NSString stringWithFormat:#"myStringWithFormat"]; // Update it to something else
myString = [NSString stringWithFormat:#"The current date is: %#", [NSDate now]]; // Update it again
All three of the above examples are immutable strings that have a collective ref count of 0. You do not need to worry about releasing or allocating them.