iOS - how to handle string concatenation when a value can be nil? - ios

I am doing something like this:
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
NSString *var1 = [standardUserDefaults objectForKey:#"obj1"];
NSString *var2 = [standardUserDefaults objectForKey:#"obj2"];
EmailUtil *email_obj = [[EmailUtil alloc] initWithSubject:#"Some subject" body:[[[#"This is var1: " stringByAppendingString: var1] stringByAppendingString:#" and var2: "] stringByAppendingString: var2]];
[email_obj send];
Where EmailUtil is just my own utility class which sends the email. This code works fine when the strings var1 and var2 are not nil; however, if they are nil the program will crash. What would be an elegant solution or good practice to follow to ensure the email is sent without a problem, regardless of what the values are?
Thanks!

Before your EmailUtil line, just add:
if(var1==nil) var1 = #"";
if(var2==nil) var2 = #"";
That should solve the crash at least.
Another and probably better way to do it would be to use NSString's stringWithFormat.
Instead of:
[[[#"This is var1: " stringByAppendingString: var1] stringByAppendingString:#" and var2: "] stringByAppendingString: var2]
Do:
[NSString stringWithFormat:#"This is var1: %# and var2: %#", var1,var2];
I believe it will say (null) for the nil parameters (didn't test this). This is probably cleaner than what I had, and your original code too.
Reference: String Format

I'd be tempted to create a NSUserDefaults category with a method that returned a guaranteed string, substituting #"" for nil or perhaps a default value that you provide. It might be overkill if your only concern (ever!) is two variables but it might also be handy for re-use.

Related

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

How can I concatenate the string that I'm using to define this label text

this seems like it is probably dead simple to somebody but I'm stuck.
I have this little app that picks a random thing from an array of things and then displays it to the user in the form of a question.
NSLog(#"How about %#?", theThing);
// How About...
self.theThingLabel.text = theThing;
//How do I add a question mark to the end of that string
in the code above the NSLog string works just like I want the label to work. I take care of the "how about" part as a string above the displayed result, but I can't figure out how to add that question mark .. something like theThing+"?"
I tried a bunch of stuff but instead of getting lucky I got warned by xcode over and over.
Try this
self.theThingLabel.text = [theThing stringByAppendingString:#" ?"];
self.theThingLabel.text = [NSString stringWithFormat:#"How about %#?",theThing];
This is very easy
Use this :
self.theThingLabel.text = [NSString stringWithFormat:#"How about %# ?", theThing];
theThing = [NSString stringWithFormat:#"How about %#?",theThing];
NSLog(#"%#", theThing);
then
self.theThingLabel.text = theThing;
Hope it helps..
NSString *what= #"What";
NSString *finalString = [NSString stringWithFormat:#"How about %# ..?", what];
NSLog(#"%#", finalString);
Hope that helps

How to pass these parameters into an NSString nsuserdefault

I have 14 nsuserdefualt save keys and instead of adding all 14 of them I created a for loop to handle this. However I am getting an error that says too many arguments. I am probably having a brain fart and forgot something. Any tips or suggestions will be appreciated.
Edit: I am trying to read the saved data.
for (int n=0; n==14; n++ ) {
NSString *emailBody=[NSString stringWithFormat:#"Enhancers: %#",
[[NSUserDefaults standardUserDefaults]
stringForKey:#"Enhancer%i",n]];
}
You had an extra argument in your format string specifically "n" that should have been placed in a different format for stringForKey:. Something like this should clear things up:
for (int n=0; n==14; n++ ) {
NSString *stringFromDefaults = [[NSUserDefaults standardUserDefaults] stringForKey:[NSString stringWithFormat:#"%d",n]];
NSString *emailBody=[NSString stringWithFormat:#"Enhancers: %#",stringFromDefaults];
}

Output to UITextField

I have a NSDictionary with some parameters i want to display in a UITextField.
but
firstname.text = [userdata objectForKey:#"firstname"];
throws an exeption.
If i use NSLog on [userdata objectForKey:#"firstname"]; it shows the right value. What seems to be the problem here?
Just use the following code:
firstname.text = [NSString stringWithFormat:#"%#",
  [userdata objectForKey:#"firstname"]];
go on .. :)
When you NSLog something it uses [object description] to convert the object to a string for output. If the object stored in your dictionary is not an NSString and you try to assign to firstname.text you will get an exception.
Another problem you may be facing is your firstname object may not be pointing at what you think it is. This may occur, for example, if you are not using ARC and you forgot to retain it or you already released it.
The exact exception you are seeing will determine which of these you are encountering.
Tried to do something like
[NSString stringWithFormat:#"%#",[userdata objectForKey:#"firstname"]];
firstname.text = nameString;
?

Using substringFromIndex on NSMutableString

Why is substringFromIndex not working for my NSMutableString ?
Here code similar to what I have :
NSMutableString *myString = [[NSMutableString alloc] initWithString:#"This is my String"];
[myString substringFromIndex:5];
NSLog(#"myString = %#", myString); //will output This is my String
If I use substringFromIndex on NSString it will work, for example like so :
NSString *tempStr = [[NSString alloc] init];
tempStr = [myString substringFromIndex:5];
NSLog(#"tempStr = %#", tempStr); //will output is my String
Why does it not work in the first example, and I have one more question, if I do it using the second method, and then I set:
[myString setString:tempStr];
[tempStr release];
This will result in a crash, I thought, since I used setString on NSMutableString, that I do not need the NSString and I release it, but apparently that is not the case, however if I use autorelease it will be OK
That method never alters the string you call it on. It returns a new string in both cases. So assign it to a new string variable and your good.
It's crashing because you over releasing one object and and leaking another. You alloc the first string, then make a new autoreleased string from substringFromIndex:, then release it. You dont need to try this hard.
Simply assign the output of the substring method to a variable, and let it be autoreleased for you. No alloc, no release.
A full proper example might look like this:
NSMutableString *myString = [[NSMutableString alloc] initWithString:#"This is my String"];
NSString *tmpString = [myString substringFromIndex:5];
NSLog(#"tempStr = %#", tempString);
[myString setString:tempStr];
// later do [myString release]
or even simpler:
NSString *myString = #"This is my String";
myString = [myString substringFromIndex:5];
You create an NSMutableString specifically so you CAN modify it.
But no one knows any way to do this:
[myMutableString substringFromIndex:5];
And if you are going to do this instead:
myMutableString = [myMutableString substringFromIndex:5];
why even use a mutable in the first place.
MutableStrings are great for ADDING (appending) to them.
Not sure why we can't also shorten (substring) them. (Without making a new copy.)
[myString substringFromIndex:5] returns a new NSString that starts from the specified index. It does not modify myString.
try this code instead:
NSLog(#"myString = %#", [myString substringFromIndex:5]);

Resources