Initialize the empty string in ObjectC? - objective-c

Someone use the following to initialize the NSstring
NSString *astring = [[NSString alloc] init];
I am wondering why not just use
NSString *atring = nil or NSString *astring = #""

There is no semantic difference between NSString *astring = [[NSString alloc] init]; and NSString *astring = #""; - but NSString *astring = nil; is completely different. The first two produce a reference to an immutable string value, the last indicates the absence of a value.
Whether the various ways of generating an zero-length string produce different objects is entirely an implementation detail. The code:
NSString *a = [[NSString alloc] init];
NSString *b = [NSString new];
NSString *c = #"";
NSString *d = [NSString stringWithString:#""];
NSLog(#"%p, %p, %p, %p, %p", a, b, c, d, #""); // %p = print the value of the reference itself
outputs (the exact values will vary):
0x7fff7100c190, 0x7fff7100c190, 0x1000028d0, 0x1000028d0, 0x1000028d0
showing only 2 zero-length string objects were created - one for #"" and one for alloc/init. As the strings are immutable such sharing is safe, but in general you should not rely on it and try to compare strings using reference comparison (==).

NSString *atring = nil
is different -- it's a nil pointer, not an empty string.
NSString *astring = #""
is almost the same, if you change it to something like
NSString* astring=[#"" retain];
It's one of the things that "don't matter"; he or she simply used one way. Probably for no particular reason at all.

NSString *atring = nil; is simply setting the pointer to nil and does nothing other than ensure that pointer is set to nil;
NSString *astring = #""; is a shorthand literal and is the equivalent of [NSString stringWithString:#""];
On another point I don't know why you would want to initialize a string to nothing if its not mutable since you won't be able to change it later without overriding it.

Related

How do I add a character to an already existing string?

When I make:
NSString x = #"test"
How do I edit it so that it becomes "testing"?
And when I put:
NSMutableString x = [[NSMutableString alloc] initWithString:#"test"];
There is an error that says:
Initializer element is not a compile-time constant.
Thanks
When declaring NSMutableString, you missed the asterisk:
NSMutableString *x = [[NSMutableString alloc] initWithString:#"test"];
// Here --------^
With a mutable string in hand, you can do
[x appendString:#"ing"];
to make x equal testing.
You do not have to go through a mutable string - this will also work:
NSString *testing = [NSString stringWithFormat:#"%#ing", test];
You need to declare your NSString or NSMutableString as *x. These are pointers to objects.
To change a string in code is quite easy, for example:
NSString *test = #"Test";
test = [test stringByAppendingString:#"ing"];
And the value in test will now be Testing.
There are a lot of great NSString methods, both instance and class methods, for manipulating and working with strings. Check the documentation for the complete list!
if you want to add multiple or single strings to an existing NSString use the following
NSString *x = [NSString stringWithFormat:#"%#%#", #"test",#"ing"];

Why is NSString stringWithString returning pointer to copied string?

I'm trying to copy an NSString value out of an NSMutableArray into a new variable. NSString stringWithString is returning an NSString with the same memory address as the object in my array. Why?
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
#autoreleasepool {
NSMutableArray *arr = [NSMutableArray arrayWithObject:#"first"];
NSLog(#"string is '%#' %p", [arr objectAtIndex:0], [arr objectAtIndex:0]);
// copy the string
NSString *copy = [NSString stringWithString:[arr objectAtIndex:0]];
NSLog(#"string is '%#' %p", copy, copy);
}
return 0;
}
1) Whenever you're creating a string using the #"" syntax, the framework will automatically cache the string. NSString is a very special class, but the framework will take care of it. When you use #"Some String" in multiple places of your app, they will all point to the same address in memory. Only when you're using something like -initWithData:encoding, the string won't be cached.
2) The other answers suggested that you should use -copy instead, but -copy will only create a copy of the object if the object is mutable. (like NSMutableString)
When you're sending -copy to an immutable object (like NSString), it'll be the same as sending it -retain which returns the object itself.
NSString *originalString = #"Some String";
NSString *copy = [originalString copy];
NSString *mutableCopy1 = [originalString mutableCopy];
NSString *mutableCopy2 = [mutableCopy copy];
NSString *anotherString = [[NSString alloc] initWithString:originalString];
--> originalString, copy, mutableCopy2 and anotherString will all point to the same memory address, only mutableCopy1 points do a different region of memory.
Since NSString instances are not mutable, the +stringWithString: method is simply returning the input string with an incremented reference count.
If you really want to force the creating of a new, identical string, try:
NSString * copy = [NSString stringWithFormat:#"%#", [arr objectAtIndex:0]];
There is little point in doing so, though, unless you need the pointer to be unique for some other reason...

Memory management, should I be retaining?

If I declare an NSString in my header file as follows:
{
NSString *testString;
}
#property(nonatomic,retain) NSString *testString;
Then synthesize the string in my .m file, what is the correct way to initialise it?
If I don't write:
self.testString = [[NSString alloc] init];
then the it is never initialised, but if I do, then isn't the string being retained twice? Or should I initialise it some other way, such as:
self.testString = [NSString stringWithFormat:#"%#, sampleText];
You are correct, the former will over retain the object.
Use the second form instead.
If you had to use the ivar directly however, you need to retain the object :
testString = [[NSString stringWithFormat:#"%#, sampleText] retain];
self.testString = [NSString stringWithFormat:#"%#, sampleText]; or self.testString = [NSString string]; is correct; self.testString = [[NSString alloc] init]; will cause over-retaining.
Consider using ARC (Automatic Retain Counting) for you project. With ARC the compiler takes care of retain counts so you don't have to, in fact aren't allowed to. There is a refactoring that will convert a current project.
It seems that you declare an variable called testString in your .h and you also create a property that retains.
You can either use this:
self.testString = [NSString string];
or you can use
testString = [[NSString alloc] init];
Defining the variable through the property will cause it to be retained, that's why you declared it as (nonatomic, retain). Defining the variable through the declaration won't take those arguments into consideration. Here's a quick rule of thumb about retaining.
Using your code as a base:
self.testString = [[NSString alloc] init]; // Retain count = 2
self.testString = [NSString string]; // Retain count = 1
testString = [[NSString alloc] init]; // Retain count = 1
testString = [NSString string]; // Not retained at all.
First of all #property (nonatomic, copy) NSString *testString to avoid mutability bugs.
Second - if you want just a string without leaks:
self.testString = [NSString string];
self.testString = [[[NSString alloc] init] autorelease];
self.testString = [NSString stringWithFormat:#"%#", text];
these are all valid options.

Change value of mutable string

How to change value of mutable string ? Here is what I do
NSString *str = #"This is string";
NSMutableString *str = [NSMutableString stringWithFormat:#"%#", str];
str = #"New string" -> wrong incompatible pointer types assigning to NSMutableString from NSString
You only need to use NSMutableString if you want to change parts of the string in place (append, insert etc.), often for performance reasons.
If you want to assign new values to the string variable, you're fine with a good old NSString as your last line simple assigns a complete new string object to str:
You can use setString to replace the whole string:
NSString *str = #"This is string";
NSMutableString *mutableStr = [NSMutableString stringWithFormat:#"%#", str];
...
[mutableStr setString:#"a different non mutable string"];
As indicated in another answer, a non-mutable NSString may be enough for your purposes.
This is how you should initialize a NSMutableString:
NSMutableString *string = [[NSMutableString alloc]init];
You could use any other way specified in the docs. The way you are doing it, you are not creating any instance of the NSMutableString class. Then, if you want to add some string to it:
[string appendString:#"content"];

Going crazy with UITextField

I'm literally going crazy whit these six rows of code.
NB: nome and prezzo are 2 textFields
NSString *itemName = (NSString *) [rowVals objectForKey:#"name"];
NSString *itemPrice = (NSString *) [rowVals objectForKey:#"price"];
nome.text = itemName;
nome.userInteractionEnabled = YES;
prezzo.text = itemPrice;
prezzo.userInteractionEnabled = YES;
Don't know why when itemPrice is copied in one of those label, the program go in SIGABRT.
Instead if I try to read the content with an NSLog(#"%#",itemPrice); it return the exact value, so it means that is a valid NSString.
The only solution I found is passing through a NSNumber:
NSNumber *itemPrice = (NSNumber *) [rowVals objectForKey:#"price"];
prezzo.text = [[NSString alloc] initWithFormat:#"%#", itemPrice];
There is another way to use directly the NSString?
Probably the value in the #"price" field is NSNumber, and not an NSString. The NSLog method will still provide a correct result, since %# is used for any NSObject subclass, not just NSString.
How about this:
NSString *itemPrice = [[rowVal objectForKey:#"price"] stringValue];
prezzo.text = itemPrice;
The problem might be the object type returned by [rowVals objectForKey:#"price"]. When you place the (NSString *) cast before the method call, you're telling the compiler what type of object is returned, but not actually converting it into an NSString. The line you use below does convert from NSNumber (or whatever other object) to a string: [[NSString alloc] initWithFormat:#"%#", itemPrice]
You might be storing NSNumber's object in NSDictionary instead of NSString.
There could be 2 ways: one would be to convert NSNumber to NSString while adding it to dictionary or the other way would be to convert NSNumber to NSString while assigning it to "itemName".
you may do the conversion for second option like:
NSString *itemPrice = [[rowVals objectForKey:#"price"]stringValue];