When should I use copy instead of using retain? I didn't quite get it.
You would use copy when you want to guarantee the state of the object.
NSMutableString *mutString = [NSMutableString stringWithString:#"ABC"];
NSString *b = [mutString retain];
[mutString appendString:#"Test"];
At this point b was just messed up by the 3rd line there.
NSMutableString *mutString = [NSMutableString stringWithString:#"ABC"];
NSString *b = [mutString copy];
[mutString appendString:#"Test"];
In this case b is the original string, and isn't modified by the 3rd line.
This applies for all mutable types.
retain : It is done on the created object, and it just increase the reference count.
copy -- It creates a new object and when new object is created retain count will be 1.
Hope this may help you.
Copy is useful when you do not want the value that you receive to get changed without you knowing. For example if you have a property that is an NSString and you rely on that string not changing once it is set then you need to use copy. Otherwise someone can pass you an NSMutableString and change the value which will in turn change the underlying value of your NSString. The same thing goes with an NSArray and NSMutableArray except copy on an array just copies all the pointer references to a new array but will prevent entries from being removed and added.
Related
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];
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.
I have been experimenting a bit with Objective-C and noted some, at least to me, rather strange behavior. First I define a pointer to an NSString and add it to an NSArray:
NSString *s = #"A";
NSArray *a = [NSArray arrayWithOject: s];
I then print out the value of s as well as the contents of a:
NSLog(#"%#", s);
NSLog(#"%#", myArray);
and in both cases the output is A. Now, if I change the pointer s, say
s = #"B";
then the two NSLog statements print out B and A, respectively.
That is, the pointer in my array still points to #"A". After spending years coding in Java, this is very surprising to me. Am I missing something really fundamental here?
Thanks,
Michael Knudsen
The easiest way to understand this is that #"A" creates a new NSString object.
In your code, you set the pointer s to point to this object, and then add the original object (not the pointer) to an array. You then change the address that the pointer points to to a new address.
If you want to change the original object, then use NSMutableString and modify the actual object (instead of changing the pointer to a new object) and they will both update as you expect.
Try:
NSMutableString *s = #"A";
// Add to array
[s setString:#"B"]
That is because NSStrings are immutable, as in Java, so you are not changing the contents of the object stored at address x (the one nsarrsy has), you are pointing s to address y.
The Java and Objective-C behaviors are the same. With the following Java code:
String foo = "foo";
Vector myVector = new Vector();
myVector.add(foo);
System.out.println(foo);
System.out.println(myVector);
foo = "bar";
System.out.println(foo);
System.out.println(myVector);
The following values are printed out:
foo
[foo]
bar
[foo]
Note: The same is true if I use String[] instead of Vector, but an NSArray is more like Vector than String[].
The easiest way to see this is to see that your s = #"B"; simply point s to another string object rather than modifying the original object.
So the array still contain #"A". When you add objects to NSArray you simply make a pointer in NSArray to point to #"A". That never changes.
Whenever I need to create a new NSString variable I always alloc and init it. It seems that there are times when you don't want to do this. How do you know when to alloc and init an NSString and when not to?
Whenever I need to create a new NSString variable I always alloc and init it.
No, that doesn't make sense.
The variable exists from the moment the program encounters the point where you declare it:
NSString *myString;
This variable is not an NSString. It is storage for a pointer to an NSString. That's what the * indicates: That this variable holds a pointer.
The NSString object exists only from the moment you create one:
[[NSString alloc] init];
and the pointer to that object is only in the variable from the moment you assign it there:
myString = [[NSString alloc] init];
//Or, initializing the variable in its declaration:
NSString *myString = [[NSString alloc] init];
Thus, if you're going to get a string object from somewhere else (e.g., substringWithRange:), you can skip creating a new, empty one, because you're just going to replace the pointer to the empty string with the pointer to the other one.
Sometimes you do want to create an empty string; for example, if you're going to obtain a bunch of strings one at a time (e.g., from an NSScanner) and want to concatenate some or all of them into one big string, you can create an empty mutable string (using alloc and init) and send it appendString: messages to do the concatenations.
You also need to release any object you create by alloc. This is one of the rules in the Memory Management Programming Guide.
If you want to initialise it to a known value, there is little point in using alloc, you can just use a string literal:
NSString* myStr = #"Some value";
If you want to initialise it with a format or whatever, but don't need it to stick around beyond the current autorelease pool lifetime, it's a bit neater to use the class convenience methods:
NSString* myTempStr = [NSString stringWithFormat:#"%d", myIntVar];
If you need its lifetime to go beyond that, either alloc/init or else add a retain to the previous call. I tend to slightly prefer the latter, but the two are pretty much equivalent. Either way you will need a balancing release later.
Note that, since NSString is not mutable, this sort of thing is not only unnecessary but actively wrong:
// don't do this!
NSString* myStr = [[NSString alloc] initWithString:#""];
myStr = someOtherStr;
since it leaks the initial placeholder value.
It seems that there are times when you don't want to do this.
I can't think of any time when I would want to alloc/init a NSString. Since NSStringgs are immutable, you pretty much always create new strings by one of:
convenience class method e.g.
NSString* foo = [NSString stringWithFormat:...];
literal
NSString* foo = #"literal";
NSString instance method
NSString* foo = [bar uppercaseString];
copy from mutable string
NSString* foo = [mutableBar copy]; // foo needs to be released or autoreleased in this case
I'm guessing that you are referring to using StringWithString or similar instead of initWithString? StringWithString alloc and inits for you under the hood and then returns an autoreleased string.
If you don't need to do any string manipulation other than to have the string, you can use NSString *str = #"string";
In general with iOS, the tighter you manage your memory the better. This means that if you don't need to return a string from a method, you should alloc init and then release it.
If you need to return a string, of course you'll need to return an autoreleased string. I don't think its any more complicated than that.
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.