How to better initialize strings to avoid dead stores - ios

I found a few questions like this but I couldn't find this particular question. I have a number of strings that are initialized as
NSString *string = [[NSString alloc] init];
which are then assigned a value depending on the results of an if/else block:
if ([anotherThing isEqualToString:#"boogers"]) {
string = [NSString stringWithFormat:#"some characters"];
} else {
string = [NSString stringWithFormat:#"some _other_ characters"];
}
and then string is used later in the method.
How can I accomplish this without leaving a dead store at the alloc/init stage? If I alloc inside the if (or the else), the string is gone by the time I need it several lines down.

You don't have to initialize the string on that first line -- you just need to declare it:
NSString *string = nil;
if ([anotherThing isEqualToString:#"boogers"]) {
string = #"some characters";
} else {
string = #"some _other_ characters";
}

The [NSString stringWithFormat:] will initialize a new NSString object for you, basically what you are doing is declaring a new object each time, just set the pointers for your strings as NSSTring *someString, *someOtherString, *allTheStringsYouNeed; and then use any class method to initialize it even #"Characters"; will work correctly as the compiler do it at runtime for you.

Related

Why two strings allocated with NSString *str1 = [[NSString alloc]init]; have same address?

NSString *str1 = [[NSString alloc]init];
NSString *str2 = [[NSString alloc]init];
NSLog(#"%p\n%p",str1,str2);
result
str1:0x7fff7b559d00
str2:0x7fff7b559d00
Why str1 and str2 have same memory address?
NSString is immutable, so two empty strings are identical. Therefore, Cocoa can return the same object every time you create it.
The real question, however, how can this be done when alloc returns two different addresses for the two strings?
The answer is that init is allowed to substitute the value of self for anything it wishes, and return a completely different object. For example, NSString's init can be implemented like this:
-(id)init {
static NSString *empty = nil;
if (!empty) {
empty = [[NSString alloc] initWithCharacters:"" length:0];
}
return empty;
}
Note: The real code in Cocoa will almost certainly be different; this is only an illustration to show how the same address could be returned for different allocations.

How does ARC deal with local variable within the method?

For example,
- (void) method
{
NSString *string = #"This is a string.";
}
Do I need to add
string = nil;
at the end of the method in order to let ARC release it?
Situation may be different in non-literal object such as
- (void) method
{
NSData *data = [[NSData alloc] init];
}
Do I need to add at the end
data = nil;
to release it?
You don't need to nil it, but ARC doesn't release it either. Since it's a literal, it's statically allocated in the app's binary. It's never released.
- (void)method {
NSString *string = #"I'm never released because I'm statically allocated";
NSString *arcReleasesMeAfterMyLastSourceRef = [NSString stringWithString:string];
}

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];

Multiple NSString declaration and initialization

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.

Objective C, what [NSString initWithFormat] exactly does?

I just would like to know the difference between the line 1 and 2 bellow:
_subtitle = #"Test"; //Line 1
_subtitle = [NSString stringWithFormat: #"Test"]; //Line 2
If I asked that question, it is because I got a problem by using MKAnnotation. In the method bellow, I try to update the subtitle delegate property of MKAnnotation (which is nonatomic, copy and readonly). But it's look like that I got a zombie when using the line 2 and nothing when using the line 1. So my question is why?
- (void) initCoordinateWithAddress:(NSString*)address;
{
self.address = address;
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString: address completionHandler:^(NSArray *placemarks,NSError *error)
{
CLPlacemark *place = [placemarks objectAtIndex:0];
_coordinate = place.location.coordinate;
_title = self.address;
_subtitle = #"Test"; //Line 1: don't crash
_subtitle = [NSString stringWithFormat: #"Test"]; //Line 2: crash
//_subtitle = [[NSString stringWithFormat: #"[%.2f,%.2f]", self.coordinate.latitude, self.coordinate.longitude] copy];
_isInit = YES;
[self.customDelegate didCalculateCoordinate: place.location.coordinate forAnnotation: self];
}];
}
I actually already fixed my problem by using the method copy, but I still not understand what is the difference between the line 1 and 2, if anyone can help me to understand what the difference is, I will appreciate.
Edit:
1- I am not using ARC
2- _subtitle comes form #synthesize subtitle = _subtitle; And subtitle is a part of the MKAnnotation protocol, with the property nonatomic, readonly and copy
Regards,
Cyril
If you are not using ARC, the answer is straightforward and is what Anoop Vaida wrote. However, I think some further explanation is needed.
This line
_subtitle = #"Test";
Creates a reference to a string literal. If you take a peak at its retain count in the current implementation of foundation, you'll find it is a very large number (NSIntegerMax I think). If the code for -release and -retain comes across this value for the retain count, they do not decrement or increment it. Thus string literals have infinite life times.
This line:
_subtitle = [NSString stringWithFormat: #"Test"];
creates a string you do not own. Unless you take steps to claim ownership, it could disappear at any time, most likely when the autorelease pool is drained. Your options are create a string you do own
_subtitle = [[NSString alloc] initWithFormat: #"Test"];
or to retain it.
_subtitle = [NSString stringWithFormat: #"Test"];
[_subtitle retain]; // Can be combined with the previous line if you like.
or to copy it
_subtitle = [[NSString stringWithFormat: #"Test"] copy];
Note that, in all cases, you need to release the previous value of _subtitle before you overwrite it, or you will get a leak e.g.
[_subtitle release];
_subtitle = [[NSString alloc] initWithFormat: #"Test"];
This is why it is better to have a property. Just because the MKAnnotation subtitle property is read only, does not mean you can't override it with your own read/write property. e.g.
#interface MyAnnotation : NSObject <MKAnnotation>
// other stuff
#property (readwrite, copy, nonatomic) NSString* subtitle;
#end
If you then synthesize it, you'll get all the correct memory management code and you can just do
[self setSubtitle: [NSString stringWithFormat: #"test"]];
or, if you must use dot notation
self.subtitle = [NSString stringWithFormat: #"test"];
I just would like to know the difference between the line 1 and 2
bellow:
_subtitle = #"Test"; //Line 1
_subtitle = [NSString stringWithFormat: #"Test"]; //Line 2
If you ask just the above these both are same.
While checking your code, the difference is quite visible.
You are creating a new autoreleased subtitle which is getting released once the block is over.
I don't think your solution is to understand how the string initializes work, but more on how blocks deal with variables.
When I think about it I think you may want to try an access _subtitle by it's property and not it's ivar.
self.subtitle
This should increment the retain count and keep everything functioning fine.
If you look up the documentation for initWithFormat: it links you to Formatting String Objects with many examples.
This basically allows (s)printf-style format strings, like so:
NSString *string1 = [[NSString alloc] initWithFormat:#"A string: %#, a float: %1.2f",
#"string", 31415.9265];
// string1 is "A string: string, a float: 31415.93"
The key is to specify arguments by adding a , after the string argument.
The '[NSString stringWithFormat:]' allows you to add a variable into the string, for example:
int myVar = 3;
NSString *myString = [NSString stringWithFormat:#"This number is %i", myVar];
The resulting string would be (if you were to NSLog it, for example): "This number is 3"
However you cannot do it like this:
NSString *myString = #"This number is %i", myVar;
Which would present you with an error.

Resources