comparing nil to integer in Objective-C - objective-c

In the following case where string is an NSString
if (string.length < 1)
{
return;
}
and string turns out to be nil the if statement will still evaluate correctly because in this case nil evaluates to 0.
However, is this recommended practice (by Clang or Apple) and are there any arguments against this and doing something closer to:
if (!string || string.length < 1)
{
return;
}

It's very common to do something like:
if (string.length) {
// string is not nil and the string has a non-zero length
} else {
// either string is nil or the length is zero
}
There is no need, in such a case, to check to see if string is nil or not.
When string is nil, you end up doing [nil length]. Calling any method on a nil pointer results in a value of "zero". How the "zero" is interpreted depends on the method's return type.
Primitive types appear as 0. BOOL appears as NO. Pointers appear as nil.

I'd say it's fine. Your alternate line is harder to understand at a glance and relies on the same logic (nil == 0) as the original line.

Some cases,for example working with strings that are made from response of requests, you should check the string, is a string, and not data!
NSString *string;
if ([string isKindOfClass:[NSString class]]) {
//
}
Cheers!

Related

Issue while comparing two strings which are nil - Objective C

I am comparing two strings.
The problem is when my both strings are nil. I don't know when both strings comes nil then why control goes in success block.
I am using this code to compare strings:
if(![oldString isEqualToString:newString])
{
//in case both are nil control reaches here
needToShowPopup = YES;
break;
}
Edit: I want if only both strings are different then only my control will go inside if statement. My condition is failing when both are nil
If you want the if condition to only be evaluated when both strings are not nil then you can do:
if (oldString && newString && ![oldString isEqualToString:newString]) {
// both strings are set but they are not the same
}
The code you have will enter the if statement if oldString is nil regardless of the value of newString.
I think you are saying that you want the equivalent of [nil isEqualToString:nil] returning true. If that is the case your if can be written:
if(oldString ? ![oldString isEqualToString:newString] : newString)
Alternatively if you don't want the if to execute if either or both values are nil then your if can be written:
if(oldString && newString && ![oldString isEqualToString:newString])
HTH
Here's how I do it
if(oldString == newString || [oldString isEqualToString:newString]) {
// strings are the same
}
The first check oldString == newString compares the pointers. Either both pointers are the same memory address so they must by definition be equal, or both pointers are nil, so also equal
If that fails, then we call [oldString isEqualToString:newString], which compares the string contents. If either side is nil, then this will return false which is what we want, but if both sides are nil it will have caught it in the previous check and we won't get here :-)
If (oldstring!=null)
{
Your code...
}

objC checking empty string, isEqualToString:#"" vs length

I have a string
NSString hi;
and I don't know what values will get initialized to it. Could be nil, could be empty string, could be anything.
Are there any advantages to using
if (![hi length])
vs
if (![hi isEqualToString:#""])
It seems like both cases return the same values for empty string, nil, and any other type of string. I would guess length is better because it's more efficient. It just returns a variable, where as isEqualToString has to do a comparison.
They don't do the same thing.
[hi length] will return 0 for nil or an empty string and nonzero for any other string.
[hi isEqualToString:#""] will return 1 when hi is an empty string and 0 when hi is nil or any non-empty string.
In other words, the only value of hi for which the two lines of code give the same result is nil.
You probably wanted the behavior of option #1 (treating either nil or an empty string as "blank" and any other value as "not blank"), so that would be the one to use.
Are there any advantages to using if (![hi length])
Yes. It can check for an empty string and for a nil at the same time. You can't do this with isEqualToString:, since if the string is nil, then any message sent to it will return zero, so it won't appear to be equal to the empty string, hence requiring another check.
By the way, for clarity, you should consider using if (hi.length != 0).
I would do the following
if (hi && ![hi isEqualToString:#""]) {
}
![hi isEqualToString:#""] alone will get you a true if hi is nil.

How to check if NSString returned by objectForKey is "" objective c

I'm not exactly sure how to check whether a NSString is blank or not, I've got this code...
NSString *imageName = [myItem objectForKey:#"iconName"];
if(imageName == #"")
{
}
And when I do a print on the myItem object, it comes up as..
iconName = "";
At the NSString *imageName line, I noticed in xcode in the console it says
"variable is not NSString"
Which I don't get as iconName is saved and stored on the parse.com database as a NSString.
When I run that code though it doesn't seem to realise that imageName = "";
You should use this code block when comparing strings:
if ([imageName isEqualToString:#""]){
}
You need to use isEqualToString to compare two strings. If you just use == then you are comparing two pointers.
You could also check to see if the object you are receiving is a NSString by:
if ([imageName isKindOfClass:[NSString class]])
Hope this helps.
Although you have a few answers already, here is my take.
First of all, your warning (not error) can be fixed like this:
NSString *imageName = (NSString *)[myItem objectForKey:#"iconName"];
Then, I would check to make sure that the string is not nil and that it is not blank. The easiest way to do this in objective-C is to check the length of the string, since if it nil it will return 0, and if it is empty, it will return 0:
if([imageName length] == 0)
{
// This is an empty string.
}
As #jlehr points out, if there is the possibility that imageName may not actually be stored as a string, then in order to prevent a crash you need to check first. (This may or may not be needed, depending on the logic of your application):
if ([imageName isKindOfClass:[NSString class]]
{
if([imageName length] == 0)
{
// This is an empty string.
}
}
The "variable is not NSString" is probably because objectForKey: return an id.
To should use [imageName isEqualToString:#""].

How do I test for null in NSDictionary from SBJSON?

I've got an API returning a JSON encoded string of data that returns a real number or "null" as a value. As long as the JSON contains a numeric or string value, everything works as expected. If the key:value pair value is null, the code below crashes.
How do I properly test NSDictionary objectForKey when it's getting a NULL from SBJSON?
When the API returns a null for filetype, the code below crashes at the if() line.
My Objective-C code attempts to test for expected values:
if (1 == [[task valueForKey:#"filetype"] integerValue]) {
// do something
} else {
// do something else
}
The API JSON output:
{"tclid":"3","filename":null,"filetype":null}
The NSLog() output of the NSDictionary is:
task {
filename = "<null>";
filetype = "<null>";
tclid = 3;
}
When transferring data from JSON to a Cocoa collection, the NSNull class is used to represent "no value", since Cocoa collections can't have empty slots. <null> is how NSNull prints itself.
To test for this, you can use someObject == [NSNull null]. It's a singleton -- there's only one instance of NSNull per process -- so pointer comparison works, although you may prefer to follow the usual Cocoa comparison convention and use [someObject isKindOfClass:[NSNull class]].
You're getting the crash because you're sending integerValue to that NSNull object. NSNull doesn't respond to integerValue and raises an exception.
You should first test if there is a value is null, if it is null performing the intValue method may crash your application.
Doing this should do.
if ([[task valueForKey:#"filetype"] isKindOfClass:[NSNumber Class]] && 1 == [[task valueForKey:#"filetype"] integerValue]) {
// do something
} else {
// do something else
}
I hope it helps.

Check if property of object instance is 'blank'

I am trying to implement the code below without success. Basically, I want to set the display name to use thisPhoto.userFullName if it is not 'Blank", else show thisPhoto.userName instead.
UILabel *thisUserNameLabel = (UILabel *)[cell.contentView viewWithTag:kUserNameValueTag];
NSLog(#"user full name %#",thisPhoto.userFullName);
NSLog(#"user name %#",thisPhoto.userName);
if (thisPhoto.userFullName && ![thisPhoto.userFullName isEqual:[NSNull null]] )
{
thisUserNameLabel.text = [NSString stringWithFormat:#"%#",thisPhoto.userFullName];
}
else if (thisPhoto.userFullName == #"")
{
thisUserNameLabel.text = [NSString stringWithFormat:#"%#",thisPhoto.userName];
}
Currently, even if userFullName is blank, my userName is still not displayed on the screen.
I'd prefer
if([thisPhoto.userFullName length])
Use -length. This will be 0 whenever the string is nil or the empty string #"". You generally want to treat both cases identically.
NSString *fullName = [thisPhoto userFullName];
thisUserNameLabel.text = [fullName length]? fullName : [thisPhoto userName];
I see a few points here
First - if your userFullName instance variable is NSString* then doing simple comparison with nil is enough:
if (thisPhoto.userFullName)
Unless, of course, you explicitly set it to be [NSNull null], which then requires the condition you wrote.
Second - comparing strings is done with isEqualToString: method so second condition should be rewritten as:
if ([thisPhoto.userFullName isEqualToString:#""]) {
...
}
Third - there's logic flaw - If your userFullName IS equal to empty string (#"") the code would still fall to the first branch. I.e. empty string (#"") is not equal to [NSNull null] or simple nil. Hence you should write to branches - one to handle empty string and nil, other one for normal value. So with a bit of refactoring your code becomes like this:
thisUserNameLabel.text = [NSString stringWithFormat:#"%#",thisPhoto.userFullName];
if (!thisPhoto.userFullName || [thisPhoto.userFullName isEqualToString:#""]) {
// do the empty string dance in case of empty userFullName.
}
If, as I suppose, thisPhoto.userFullName is a NSString you may try
[thisPhoto.userFullName isEqualToString:#""]
The other two answers are correct, and beat me to it. Rather than just repeat what they have said - I'll point out something else.
[NSNull null] is used to store nil values in collection classes (NSArray, NSSet, NSDictionary) that don't allow nil values to be stored in them.
So unless you're checking values that you get from a collection - there is no point checking against [NSNull null]
// this assumes userFullName and userName are strings and that userName is not nil
thisUserNameLabel.text = [thisPhoto.userFullName length] > 0 ? thisPhoto.userFullName : thisPhoto.userName;
"Blank" means #"", but also #" " or #"\n". So I would trim userFullName and check the length of that string.
if ([[thisPhoto.userFullName stringByTrimmingCharactersInSet:
[NSCharacterSet whitespaceAndNewlineCharacterSet]] length] == 0) {
// it's blank!
}