is NSString value cannot be changed once it is provided a value? - iphone

Hi I got an information that NSString value is immutable and cannot be changed once it is provided a value.
But I have created and tested the following code:
NSString *str=[[NSString alloc] initWithString:#"Hello"];
NSLog(#"\n\nstr = %#",str);
str=#"asdasd";
NSLog(#"\n\n new str = %#",str);
and this gives "Hello" as first str value and "asdasd" as second str value. If it is so what is the relevance of calling NSString immutable?Thanks in advance.

What you're doing on the third line is just creating a new string and pointing it with the str variable. You didn't change the original string, but rather made the variable point to a new one.

NSString is immutable. You cannot mutate it. Your confusion arises from the fact that your variable (pointer) is not const.
All you're doing is reassigning the pointer to a different immutable string.
If you were to attempt to append a string to either, then an error would ensue. This, specifically, is "…the relevance of calling NSString immutable". You should interpret this as the string instance may not be mutated, even though the variable you have declared may be assigned another NSString instance because it is not const.
You can make both the pointer const and the string immutable like so:
NSString * const aStr = #"aStr";

You're confusing an immutable object and a constant pointer (plus you're leaking memory). Here you don't really change the NSString instance (that is, the object itself), but just a pointer to it. The point is that you can assign different instances of an NSString to the same variable, it won't change the internal contents of the object, nor would it make it respond to NSMutableString's mutation messages such as appendString etc.

Use this will sol your problem...
NSString *str=[NSString stringWithFormat:#"Hello"];
NSLog(#"\n\nstr = %#",str);
str = nil;
str=#"asdasd";
NSLog(#"\n\n new str = %#",str);
This some basic that you should know..
NSString *s1 = #"string1";
NSString *s2 = [[NSString alloc] initWithString:#"string2"];
NSString *s3 = [NSString stringWithFormat:#"string3"];
s1 in this case is a pointer to a constant string. s2 and s3 both point to new strings that you've created, but s2 has been retained for you, and s3 has been autoreleased. If you just need a temporary object, the autoreleased object s3 or the constant object s1 are good choices. If you need to keep the string around, you should use s2 (actually now that I think about it s1 will work in this case too - it's not really idiomatic, though).
You can make s1 or s3 equivalent to s2 by sending them a retain message. You could also turn s2 into an equivalent object by sending it an autorelease message.

Related

NSLog pointer syntax

I'm a little bit confused about the syntax of NSLog. For example,
NSString *nameString = #"Name";
NSLog(#"nameString is: %#", nameString);
If my understanding is correct (which it very well may not be), then nameString is defined to be a pointer to a String. I thought then that this would print the memory address that nameString holds, not the value of that address. So, if that is true, then in the NSLog statement, to get the value of the pointer, shouldn't we need to use the asterisk notation to access what nameString points to like this:
NSLog(#"nameString is: %#", *nameString);
?
It has been a little while since programming in C, but since Objective-C is a superset of C I thought they would behave similarly.
An explanation would be greatly appreciated! Thanks!
The command %# is like "shortcut" that calls the method -description on the receiver. For an NSString it simply display the string itself, since is inherited from NSObject you can override it, very usefull if you create for own class. In that case the default behaviur is print the value of the pointer. If you want to print the address of the pointer in the string just replace with :
NSLog(#"nameString is: %p", nameString)
I think that you use an asterisk only to declare a pointer. Then, you only use the name you decided. For example:
NSString *foo = [[NSString alloc] initWithString:#"Hello"];
NSLog(#"%#", foo);
Correct me if I am wrong :)
It's an object and NSLog is a function that uses its format specifiers to determine what to do with the argument. In this case the specifier is %# which tells NSLog to call a method on an object.
Normally this will call the method "description" which returns an NSString but it probably does respondsToMethod first and falls through to some other string methods.

Getting an error when using replaceOccuranceOfString function

[str replaceOccurrencesOfString: withString: options: range:
[str replaceOccurrencesOfString:#"'" withString:#"!~" options:0 range:NSMakeRange(0,str.length)]
I am using this function to replace ' symbol in my NSMutableString with !~ symbol so that I can store that string into database. Its working fine when I stored it into database, but at the time of retrieving and convert it back using same function it showing me error like.
Error
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attempt to mutate immutable object with replaceOccurrencesOfString:withString:options:range:'
Here, str is of NSMutableString type. I checked for its type [str class] its converts to NSCFString don't know why its changing? I also try to convert it to NSMutableString, but its not converting. I am trying for it for so many times in some other ways, but its working fine with all other places, only in my one view controller, it showing me this.
Any guesses where's I am doing wrong?
You don't show how you are converting the immutable from the data base to a mutable string. Just doing NSMutableString *mstr = str; isn't enough, you'd need to use NSMutableString *mstr = [NSMutableString stringWithString:str];.
Because the returned string is immutable you might want to consider using [NSString stringByReplacingOccurrencesOfString:withString:] instead of working with mutable strings.

Convert or Print CGPDFStringRef string

How to convert a CGPDFStringRef to unicode char? I have used CGPDFStringCopyTextString to get the string and then [string characterAtIndex:i] to cast to unichar, is this the right way? or is there any way to get the bytes of the string and convert to unicode directly?
Need some guidance here.
NSString is capable of handling of unicode characters itself, you just need to convert the CGPDFString to NSString and further you can use it as follows:
NSString *tempStr = (NSString *)CGPDFStringCopyTextString(objectString);
although UPT's answer is correct, it will produce a memory leak
from the documentation:
CGPDFStringCopyTextString
"...You are responsible for releasing this object."
the correct way to do this would be:
CFStringRef _res = CGPDFStringCopyTextString(pdfString);
NSString *result = [NSString stringWithString:(__bridge NSString *)_res];
CFRelease(_res);
It's not a bad idea, even if you can access the CGPDFString directly using CGPDFStringGetBytePtr. You will also need CGPDFStringGetLength to get the string length, as it may not be null-terminated.
See the documentation for more info

Explain the difference between mutable and immutable

What is the difference between mutable and immutable?
Such as:
NSString vs NSMutableString.
NSArray vs NSMutableArray.
NSDictionary vs NSMutableDictionary.
What is the difference between a mutable object and the other object [which I assume is immutable]?
A mutable object can be mutated or changed. An immutable object cannot. For example, while you can add or remove objects from an NSMutableArray, you cannot do either with an NSArray.
Mutable objects can have elements changed, added to, or removed, which cannot be achieved with immutable objects. Immutable objects are stuck with whatever input you gave them in their [[object alloc] initWith...] initializer.
The advantages of your mutable objects is obvious, but they should only be used when necessary (which is a lot less often than you think) as they take up more memory than immutable objects.
The basic difference is:
NSStrings cannot be edited, only reassigned. This means when the value of an NSString changes, it is actually pointing to a new location in memory.
NSMutableString objects can be edited and maintain the same pointer.
A common practical difference is:
If you create 1 NSString and then assign another one to it, then edit either one of them, they will now be pointing to different strings.
If you do the same thing with NSMutableStrings, but then just edit one of them (not reassign it), they will both be pointing to the newly edited object.
Mutable objects can be modified, immutable objects can't.
Eg:
NSMutableArray has addObject: removeObject: methods (and more), but NSArray doesn't.
Modifying strings:
NSString *myString = #"hello";
myString = [myString stringByAppendingString:#" world"];
vs
NSMutableString *myString = #"hello";
[myString appendString:#" world"];
Mutable objects are particularly useful when dealing with arrays,
Eg if you have an NSArray of NSMutableStrings you can do:
[myArray makeObjectsPerformSelector:#selector(appendString:) withObject:#"!!!"];
which will add 3 ! to the end of each string in the array.
But if you have an NSArray of NSStrings (therefore immutable), you can't do this (at least it's a lot harder, and more code, than using NSMutableString)
A mutable object can be mutated or changed. An immutable object cannot. For example, while you can add or remove objects from an NSMutableArray, you cannot do either with an NSArray.
The english definition of "mutable" is really all you need here. Mutable objects can be modified after creation. Immutable objects cannot be modified after creation. That applies to all of the classes you listed.
Practically speaking, all of the mutable classes are subclasses of the immutable ones, and each adds its own interface to allow programmatic modification of the object, like addObject:, setObject:forKey:, etc...
Everyone says you can't change/modify an immutable object. I have a different way of explaining. You can modify it, but then you would be creating a new pointer to the new object, its not like you modified the old object, its a brand. New. Object. Any pointer that had a previously pointing pointer to it, would not see its change. However if its a Mutable Object, any previously pointing object to it would be seeing its new value. See the examples.
FYI %p prints the pointer location in heap.
NSString * A = #"Bob";
NSString * B = #"Bob";
NSString * C = #"Bob1";
NSString * D = A;
NSLog(#"\n %p for A \n %p for B \n %p for C \n %p for D",A,B,C,D);
// memory location of A,B,D are same.
0x104129068 for A
0x104129068 for B
0x104129088 for C
0x104129068 for D
Modifying pointer A's object
A = #"Bob2"; // this would create a new memory location for A, its previous memory location is still retained by B
NSLog(#"\n%p for A \n%p for B \n%p for C \n %p for D",A,B,C, D);
// A has a **new** memory location, B,D have same memory location.
0x1041290c8 for A
0x104129068 for B
0x104129088 for C
0x104129068
for D
// NSMutableString * AA = #"Bob"; <-- you CAN'T do this you will get error: Incompatible pointer types initializing NSMutableString with an Expression of type NSString
NSMutableString * AA = [NSMutableString stringWithString:#"Bob1"];
NSString * BB = #"Bob";
NSString * CC = #"Bob1";
NSString * DD = AA;
NSLog(#"\n %p for AA \n %p for BB \n %p for CC \n %p for DD",AA,BB,CC,DD);
// memory location of AA,DD are same.
0x7ff26af14490 for AA
0x104129068 for BB
0x104129088 for CC
0x7ff26af14490 for DD
Modifying pointer AA's object
AA = (NSMutableString*)#"Bob3"; // This would NOT create a new memory location for A since its Mutable-- D was and still pointing to some location
NSLog(#"\n%p for AA \n%p for BB \n%p for CC \n %p for D",AA,BB,CC,DD);
// memory location of AA,DD are NOT same.
0x104129128 for AA
0x104129068 for BB
0x104129088 for CC
0x7ff26af14490 for DD
As you would imagine, the default storage attribute for all NSString properties is retain. For more information on copy & retain I highly suggest you read this question.NSString property: copy or retain?
Mutable can be changed, immutable cannot.
When you share a mutable objects, you should expected the some one can change it.
When you share an immutable object, you expected the no one will changed.
There are some other difference which are interesting a immutable object when copied will instead be retained. There may also be lots of under the hood differences that apple implements for performance reason depend on whether a object is mutable or not, for example, do the substring methods copy the actual bytes of their parent string or do the just point a subrange of the parent string if it is immutable, probable not but who knows.
Immutability as: “not capable of or susceptible to change” and mutability as “capable of change or of being changed”.
To rephrase immutable means can’t be changed and mutable means can be changed.
In swift code, we apply the concepts of immutability and mutability using the keywords let and var respectively.
for more detail visit this link it has detail description with code
Mutable variables
// Declaration and assignment of a mutable variable name.
var name = "Kory"
// Reassignment or mutation of the variable name.
name = "Ryan"
Above we declared a variable named “name” and assigned its value to be the String literal “Kory”. On line five we reassigned the variable to be the String literal “Ryan”.
This is an example of a mutable variable. Using the keyword var allows us to change the value the variable holds. The variable “name” can be changed to whatever String we like.
Mutable variables are needed when the value of a variable is expected to change. Let’s take a look at a slightly more complicated example.
// Declares a new type Person
struct Person {
var name: String
var age: Int
}
// Creates an instance of person named kory.
var kory = Person(name: "Kory", age: 30)
// Mutates Kory's properties
kory.age = 31
kory.name = "Scooby"
In the above example both the name and age properties of instance of a Person are mutable, they can be changed. In this example mutability is important. A person’s name or age can and will change in real life. Having mutable variables allows our data too closely resemble the real world thing we are trying to model.
Immutable contants
Often the words variable and constants are used interchangeably but there is a subtle difference. Mutability. Variables as the name implies can vary with the data they hold. Constants cannot and are therefore are immutable and in other words constant. Swift allows us to represent an immutable constant with the keyword “let”. Consider the below example.
// Declaration and assignment of a mutable variable name.
let name = "Kory"
name = "Ryan" // Cannot assign to property: 'name' is a 'let' constant
The above example is nearly identical to the mutable example but will not compile. When an identifier such as “name” is set to be immutable with the keyword “let” it cannot be changed once assigned. You can delay assignment as illustrated below. But you cannot change name once it has been assigned.
let name: String
// Some important code here
name = "Kory"
You can also use constants inside of structs and classes when you want to make one or more properties immutable even if the instance is declared as mutable.
// Declares a new type Person with constants properties
struct Person {
age name: String
let age: Int
}
var kory = Person(name: "Kory", age: 30)
kory.name = "Ryan"
kory.age = 30 // Cannot assign to property: 'age' is a 'let' constant
Even though kory is declared with var, internally age is declared with let and cannot be mutated. Mutating name is fine.

ObjectiveC Parse Integer from String

I'm trying to extract a string (which contains an integer) from an array and then use it as an int in a function. I'm trying to convert it to a int using intValue.
Here's the code I've been trying.
NSArray *_returnedArguments = [serverOutput componentsSeparatedByString:#":"];
[_appDelegate loggedIn:usernameField.text:passwordField.text:(int)[[_returnedArguments objectAtIndex:2] intValue]];
I get this error:
passing argument 3 of 'loggedIn:::' makes pointer from integer
without a cast
What's wrong?
I really don't know what was so hard about this question, but I managed to do it this way:
[myStringContainingInt intValue];
It should be noted that you can also do:
myStringContainingInt.intValue;
You can just convert the string like that [str intValue] or [str integerValue]
integerValue
Returns the NSInteger value of the receiver’s text.
(NSInteger)integerValue
Return Value
The NSInteger value of the receiver’s text, assuming a decimal representation and skipping whitespace at the beginning of the string. Returns 0 if the receiver doesn’t begin with a valid decimal text representation of a number.
for more information refer here
NSArray *_returnedArguments = [serverOutput componentsSeparatedByString:#":"];
_returnedArguments is an array of NSStrings which the UITextField text property is expecting. No need to convert.
Syntax error:
[_appDelegate loggedIn:usernameField.text:passwordField.text:(int)[[_returnedArguments objectAtIndex:2] intValue]];
If your _appDelegate has a passwordField property, then you can set the text using the following
[[_appDelegate passwordField] setText:[_returnedArguments objectAtIndex:2]];
Basically, the third parameter in loggedIn should not be an integer, it should be an object of some kind, but we can't know for sure because you did not name the parameters in the method call. Provide the method signature so we can see for sure. Perhaps it takes an NSNumber or something.
Keep in mind that international users may be using a decimal separator other than . in which case values can get mixed up or just become nil when using intValue on a string.
For example, in the UK 1.23 is written 1,23, so the number 1.777 would be input by user as 1,777, which, as .intValue, will be 1777 not 1 (truncated).
I've made a macro that will convert input text to an NSNumber based on a locale argument which can be nil (if nil it uses device current locale).
#define stringToNumber(__string, __nullable_locale) (\
(^NSNumber *(void){\
NSLocale *__locale = __nullable_locale;\
if (!__locale) {\
__locale = [NSLocale currentLocale];\
}\
NSString *__string_copy = [__string stringByReplacingOccurrencesOfString:__locale.groupingSeparator withString:#""];\
__string_copy = [__string_copy stringByReplacingOccurrencesOfString:__locale.decimalSeparator withString:#"."];\
return #([__string_copy doubleValue]);\
})()\
)
If I understood you correctly, you need to convert your NSString to int? Try this peace of code:
NSString *stringWithNumberInside = [_returnedArguments objectAtIndex:2];
int number;
sscanf([stringWithNumberInside UTF8String], "%x", &flags);