Multiple NSString declaration and initialization - ios

I am new to the ios development.I was checking the NSString and where I had found out that it was excessed using the multiple ways which is as under
1) NSString *theString = #"hello";
2) NSString *string1 = [NSString stringWithString:#"This is"];
3) NSString *string =[[NSString alloc]init];
string =#"Hello";
Now I am confused with above three and would like to know the differences between then?

Yes all three are ways to create string...I try to explain you one by one.
One think you must remember that in Objective-c string is represented by #"".
whatever comes double quotes is string eg #"Hello" is string. #"" is basically literal to create NSString.
NSString *theString = #"hello";
EDIT:
In this statement we are creating an NSString constant. Objective-C string constant is created at compile time and exists throughout your program’s execution.
2. NSString *string1 = [NSString stringWithString:#"This is"];
In this statement again, we are creating an autorelease object of NSString, but here a slide diff. than the first case. here we are using another NSString object to create a new autorelease object of NSString. So generally we use stringWithString method when we already have NSString Object and we want another NSString object with similar content.
3. NSString *string =[[NSString alloc]init];
string =#"Hello";
Here, In first statement you are creating a NSString Object that you owned and it is your responsibility to release it (In non-ARC code), once you done with this object.
Second statement is similar to case 1, by string literal you are creating string Object.
but when you put these two statements together it causes you memory-leak(In non-ARC code), because in statement one you are allocating & initiating memory for new string object and right after in second statement you are again assigning a new string object to the same string reference.

1) and 2) is the same. there is no difference. [NSString stringWithString: str] just does nothing and returns str if str is immutable already. via this link
3) you create empty NSString pointer. after you assign this string with ' = ' is same way with 1) and it alloc memory to your NSString. You can watch this NSString pointer in 3) and you see pointer was changed:
NSString *string =[[NSString alloc]init];
printf("\n string_1-> = %p\n", string );
string = #"Hello";
printf("\n string_2-> = %p\n", string );

OK, first off, the syntax #"blah" is an Objective-C literal to create an NSString. Essentially it is an NSString.
Also, there are two parts to each statement. The declaration of the string variable NSString *string and the instantiation string = <something>.
So...
This is how you would do it most of the time. You declare the variable and set it using the objective-c literal.
This adds a bit of redundancy and you wouldn't really use it like this. You'd maybe use it with a substring or something from another string. As it is you are essentially creating two objects here. The first is [NSString stringWithString:<>]; and the second is #"This is".
This is a bit odd. You are first creating an empty string #"" and then you are replacing this string with #"Hello". Don't do this. There is no point. You may as well just do number 1 as the result is the same.
All three will work but in these exact cases you'd be better off using the first.

Related

how to replace the content of NSMutablestring in objective c

I am new in objective c. I want to replace the content of mutable string I am using code as
NSMutableString *myMutableStringObj = [myMutableStringObj stringByReplacingOccurrencesOfString:#" & " withString:#"And"];
But It Shows me warning
Incomparable pointer types assigning to NSMutableString * from NSString *
Any Suggestion about this. I am using MutableString.
It tells you this function returns NSString *. If you want to clean that warning. Just do like this:
NSMutableString *myMutableStringObj = [[myMutableStringObj stringByReplacingOccurrencesOfString:#" & " withString:#"And"] mutableCopy];
See the method signeture from NSString Class.
- (NSString *)stringByReplacingOccurrencesOfString:(NSString *)target
withString:(NSString *)replacement
this method return NSString object.
So you need to convert result into mutalbe string or catch the result in NSString.
Read the documentation for NSString and NSMutableString. That doesn't only apply to you, but to anyone answering here so far. The answers on this thread have been absolutely depressing.
There are methods that can be used for NSString but also work with NSMutableString which create a new, immutable string based on a previous string. Typically methods starting with "stringBy..." will be creating a new string.
And there are methods, in the NSMutableString interface, which modify the contents of an existing NSMutableString. Like "replaceOccurencesOfString".
Read the documentation and pick what is right for you. A method starting with "stringBy" is not going to modify your mutable string, it's creating a new immutable one. To modify a string, use the methods from the NSMutableString interface. Fortunately the compiler tells you when you use the wrong method.
plz use this code
NSMutableString * str1 = [NSMutableString stringWithString:#"Hello Testing"];
str1 = [[str1 stringByReplacingOccurrencesOfString:#"T" withString:#"B"] mutableCopy];
NSLog(#"%#",str1);

What exactly does #"" do behind the scenes?

When giving a NSString a value using = #"", what exactly is that shorthand for? I noticed that, all other things being equal in an application, global NSStrings made with #"" don't need retain to be used outside of the methods that gave them that value, whereas NSStrings given a value in any other way do.
I have found this question utterly unsearchable, so I thank you for your time.
A related answer: Difference between NSString literals
In short, when writing #"" in the global scope of your program, it does the same as writing "": The literal string you specified will be embedded in your binary at compile time, and can thus not be deallocated during runtime. This is why you don't need release or retain.
The # just tells the compiler to construct a NSString object from the C string literal. Mind you that this construction is very cheap and probably heavily optimized. You can follow the link and see this example:
NSString *str = #"My String";
NSLog(#"%# (%p)", str, str);
NSString *str2 = [[NSString alloc] initWithString:#"My String"];
NSLog(#"%# (%p)", str2, str2);
Producing this output:
2011-11-07 07:11:26.172 Craplet[5433:707] My String (0x100002268)
2011-11-07 07:11:26.174 Craplet[5433:707] My String (0x100002268)
Note the same memory addresses
EDIT:
I made some test myself, see this code:
static NSString *str0 = #"My String";
int main(int argc, const char * argv[]) {
NSLog(#"%# (%p)", str0, str0);
NSString *str = #"My String";
NSLog(#"%# (%p)", str, str);
NSString *str2 = [[NSString alloc] initWithString:#"My String"];
NSLog(#"%# (%p)", str2, str2);
return 0;
}
Will produce this output:
2015-12-13 21:20:00.771 Test[6064:1195176] My String (0x100001030)
2015-12-13 21:20:00.772 Test[6064:1195176] My String (0x100001030)
2015-12-13 21:20:00.772 Test[6064:1195176] My String (0x100001030)
Also, when using the debugger you can see that the actual object being created when using literals are in fact __NSCFConstantString objects.
I think the related concept to that is called Class Clusters
Objective-C is a super-set of C, which means you should be able to write C code in there and have it work. As a result, the compiler needs a way to distinguish between a C string (an old-school series of bytes) and an Objective-C NSString (Unicode support, etc). This is done using the # symbol, such as #"Hello".
#"Hello" can't be released because it's a literal string – it's been written into the program when it was built, versus being assigned at run-time.
String allocated using the literal syntax i.e # reside as c strings in the data segment of the executable. They are allocated only once at the time of program launch and are never released until the program quits.
As an exercise you can try this:
NSString *str1 = #"Hello";
NSString *str2 = #"Hello";
NSLog("Memory Address of str1 : %p", str1);
NSLog("Memory Address of str2 : %p", str2);
both the log statements will print the same address which means literals are constant strings with lifetimes same as that of the program.

How can i implement the same behaviour as in cluster pattern by apple (NSString and NSCFString)

I am simply writing the following code for testing purpose:
NSString *aStr = [[NSString alloc] initWithFormat:#"Foo"];
aStr = [aStr initWithFormat:#"Bar"];//Crashed here
I am getting the following error:
*** initialization method -initWithFormat:locale:arguments: cannot be sent to an abstract object of class __NSCFString: Create a concrete instance!
If i write the following code same thing happen
NSString *aStr = [NSString alloc];
aStr = [aStr initWithFormat:#"Foo"];
aStr = [aStr initWithFormat:#"Bar"]; //Crashed here
By google I come to know that initWithFormat will return the NSCFString Object.
My question is if NSCFString is derived class of NSString then why I cannot invoke the initWithFormat method on NSCFString. If it is possible to stop the visibility how can I implement in the code without overriding the method in NSCFString(Derived Class).
In simple word If NSCFString is derived class of NSString then why i cannot call the base class (initWithFormat) method on that?
I believe that what's happening is that the [NSString initWithFormat:] method is noticing that you have not provided any format specifiers so there is no NSString object that needs building, so it's simply returning the constant NSString object you pass in (#"Foo"):
NSString *aStr = [NSString alloc];
aStr = [aStr initWithFormat:#"Foo"];
So aStr is now of type NSCFString. This is the cause of the crash:
aStr = [aStr initWithFormat:#"Bar"]; //Crashed here
However you should never be calling an init method on an existing object, so to correct the crash use:
aStr = [[NSString alloc] initWithFormat:#"Bar"];
and use format specifiers as you may as well just do:
aStr = #"Foo";
aStr = #"Boo";
which is the same thing only clearer, uses less code and has better performance.
As per Documentation it returns an NSString object initialized by using a given format string as a template into which the remaining argument values are substituted.
And also you need to use like that below :-
NSString *aStr = [[NSString alloc] initWithFormat:#"%#,%#",#"Foo",#"Bar"];
NSLog(#"%#",aStr);
You are asking "why". Besides the answer "calling init twice on the same object is baaaad" which you ignored, NSString is a class cluster.
[NSString alloc] returns a generic object that isn't really usable as a string but expects an init method to be called. Let's think about something obvious: NSString objects are immutable, but the result of [NSString alloc] cannot be immutable, because otherwise it would be impossible to store a value, right?
That init method will actually return a different object that doesn't accept init methods anymore. While [NSString alloc] is a very flexible object that could do anything, after a call to an init method you get an object back that contains a string that can never be modified again.
(Apple may have implemented this differently from what I say or may change their implementation. Nevertheless, they can and will do things that stop you from doing something stupid).
And a warning: Don't even think about subclassing NSString. I can guarantee that you won't get anything cobbled together that works.

Peculiar issue with wiping the underlying buffer of NSString

I am using a technique outlined in the book Hacking and Securing iOS Applications (relevant section here) to wipe the underlying buffer of a NSString as shown below.
NSString *s = [NSString stringWithFormat:#"Hello"];
unsigned char *text = (unsigned char*)CFStringGetCStringPtr((CFStringRef)s, CFStringGetSystemEncoding());
if (text != NULL)
{
memset(text, 0, [s length]);
}
This works, unless the string is a certain value.
// The following crashes with EXC_ACCESS_ERROR on memset
NSString *s = [NSString stringWithFormat:#"No"];
NSString *s = [NSString stringWithFormat:#"Yes"];
// These work fine though
NSString *s = [NSString stringWithFormat:#"Hello"];
NSString *s = [NSString stringWithFormat:#"Do"];
NSString *s = [#"N" stringByAppendingString:#"o"];
It looks like certain strings are not created on the heap but is optimized by making it point to a read-only string table even if the string is created on the heap.
Indeed constant string are not created on the heap and are in read-only memory. This includes a few that look like runtime but are made compile-time constants, your examples are such statements.
With this statement fragment there is no reason not to make it a compile-time constant.
[NSString stringWithFormat:#"No"]
it is equivalent to:
#"No"
Suggestion, file a bug report requesting a secure string class, I have. Several have been filed and I have been told that if there are enough (whatever that amount might be) are files it will implement it.
It is possible to subclass NSString, not easy but you will have compete control of the actual buffer and it should not be subject to possible failure due to Apple changing the implementation detail. I have done that successfully.
NSString *s = [NSString stringWithFormat:#"No"]; will be optimised to NSString *s = #"No"; because there are no substitutions in the format. Assigning a literal will give you a pointer to the readonly text segment of the loaded binary.
NSString *s = [#"N" stringByAppendingString:#"o"]; will create a new string on the heap and return a reference to it. The heap is read-write even though the datatype NSString is readonly.
When you get the CString pointer to the underlying data it's pointing either into read-only data in the first case, or read-write data in the second. The memset will fail on the readonly memory, but succeed on the read-write.

Adding NSString to NSMutableString

I want to add multiple NSStrings yo an NSMutableString to construct a list of strings.
This is my code in a method that takes an NSDictionary and grabs the value out of it - it then stores it in an NSString, From there I append the string to the NSMutableString. When running this method for the first time it works. However, when I call the method again, it replaces the last string that was in the NSMutableString.
Here is the code:
NSString *userId = [NSString stringWithFormat:#"%#,", parameters[#"userId"]];
self.alluserIds = [NSMutableString string];
[self.alluserIds appendString:userId];
Can anyone tell me what I am doing wrong?
self.alluserIds is declared strong.
This:
self.alluserIds = [NSMutableString string];
is creating a new mutable string. It should be done once, before you want to use the mutable string, and not done again until you want to restart (because recreating the mutable string destroys the old instance you had).
This is happened because you call:
self.alluserIds = [NSMutableString string];
This create new string and assign it to self.alluserIds. You should call it just once in for example init method or viewDidLoad.
You should initialize with the string you are using and it should be a single initialization your code should look like below.
NSString *userId = [NSString stringWithFormat:#"%#,", parameters[#"userId"]];
if(!self.alluseIds)
self.alluserIds = [[NSMutableString alloc] initWithString:userId]; //ONLY Initialization
else
[self.alluserIds appendString:userId];
Hope this helps
I don't know your data-structure, but if you might have all userids in an array you could join them together with componentsJoinedByString::
NSArray *pathArray = [NSArray arrayWithObjects:#"here", #"be", #"dragons", nil];
NSLog(#"%#",[pathArray componentsJoinedByString:#" "]);
Don't use mutable strings(and mutable collections too) except cases you really need it: http://rypress.com/tutorials/objective-c/data-types/nsstring.html (When To Use Mutable Strings) You have to use them when you want to make a lot of operations. Immutable collections are slower because you create new instance when append another string.
How to do this with NSString:
self.alluserIds = [self.alluserIds stringByAppendingString: userId];

Resources