String Passes Empty Test, Returns null - ios

I am testing to see if a string is stored in NSUserDefaults. In theory, I thought the following was the answer:
if ( ![[[NSUserDefaults standardUserDefaults] authorName] isEqual: #""] )
{
NSLog(#"The default must be set, the string is not equal to empty.");
NSString *authorName = [[NSUserDefaults standardUserDefaults] authorName];
}
In practice, it always tested that something was there, but then returned a value of "(null)", when I try to use it. Can someone tell me why?
Ultimately, I think I've solved the problem with the following, but I'm not clear why the first test case did not work as I expected.
if ( [[[NSUserDefaults standardUserDefaults] authorName] length] != 0 )
Thanks.

The nil string is not equal to the empty string. That is why the first test passes but returns nil - because NSUserDefaults will return nil if no value is stored.
The reason why comparing length to zero works, is because when calling a method on a nil reference in objective-c, nil is returned. This is different from most other language, which would instead throw an exception in this case. Because length is NSInteger, nil becomes zero.
Comparing length to zero should be safe, but what you really is trying to test is whether a string is stored for the given key in the defaults. In that case, you can simply compare to nil:
if ([[NSUserDefaults standardUserDefaults] authorName] != nil)
{
....
}

Related

Objective C syntax issue related to parameter not getting right data

I've been working on a project implementing Hola CDN framework. I'm now running into an issue that I can't pass on current date to the parameter programDay and I traced the source code and I found the below line. What does this below line mean?
self.programDay = ![dict[GETPROGRAMLISTDATA_PROGRAMEDAY] isEqual:[NSNull null]] ? dict[GETPROGRAMLISTDATA_PROGRAMEDAY] : nil;
What's NSNull
[NSNull null] doesn't equal to nil. It means empty value. For example,
#[[NSNull null]].count equals to 1. NSNull is used as placeholder in NSArray and NSDictionary. It means nil.
For your question
This line is used to replace NSNull with nil.
self.programDay = ![dict[GETPROGRAMLISTDATA_PROGRAMEDAY] isEqual:[NSNull null]] ? dict[GETPROGRAMLISTDATA_PROGRAMEDAY] : nil;
This line means that if [dict[GETPROGRAMLISTDATA_PROGRAMEDAY] has empty value or null value the nil would be assign to self.programDay as there would be value of [dict[GETPROGRAMLISTDATA_PROGRAMEDAY] will be assign to self.programDay. Usually (null) value is return from webservice if that value is not presented in database on server.

How to handle NSNull values

In Objective C, a common practice is to often forgo checking for nil, instead relying on the fact that messaging nil silently fails.
For example, to validate a string:
if ([myString length] > 1) { // Short and sweet
If myString is nil, this check will fail - as intended. It's a huge improvement over what one may assume would be the correct implementation, explicitly checking for nil:
if (myString && [myString length] > 1) { // Redundant nil check
However, particularly in the case of a web API, myString could conceivable equal [NSNull null] - similar to nil, but with different behavior. Of primary concern, is that messaging NSNull causes an exception. For example, our short simple solution from earlier will cause an exception:
// Causes an exception, because [NSNull null] is an object
NSString *myString = (id)[NSNull null];
if ([myString length] > 1) {
To further complicate things, a simple nil check will actually pass because [NSNull null] is a valid object:
NSString *myString = (id)[NSNull null];
if (myString) { // Evals to YES
So, the only way to be completely safe is to both check for NSNull and do your regular implicit nil check, by calling a method:
if (myString != (id)[NSNull null] && [myString length] > 1) { // Short and sweet
My Question: is this really necessary? Is there a more concise option with less duplicate code, that I've overlooked? Are my conclusions, in fact, correct?
NSNull objects typically crop up with people reading JSON files containing null values.
In that case, there is a chance that the server that supplied the null value thinks you should do something different than with no value. For example, if you get a dictionary and there might be a string stored under some key, you might get a string with non-zero length, you might get an empty string because the server sent you an empty string, you might get nothing because the server sent you nothing, or you might get [NSNull null] because the server sent you a null value. Up to you to decide if the empty string, nothing, and [NSNull null] need to be treated differently or not.
By the way: I have always used some extensions to the NSDictionary class, for example - (NSString*)stringForKey, which will return either an NSString or nil, 100% guaranteed. If you do that, all your error checking is in one method. And you can do things like converting NSNumber to NSString, or NSNull to nil, or NSDictionary etc. to nil, and never worry about it again. Of course you need to check if it is appropriate.
is this really necessary?
If some API can return NSNull instead of a string, then yes, you should check for it. It's usually not necessary since NSNull is not a string and won't be returned by most methods that would return a string. But a collection such as a dictionary, for example, can have any object as a value. If you're not sure that the value will be a string, you should take appropriate precautions.
Is there a better way to handle the possibility of NSNull that I've overlooked?
Another way that you could do roughly the same thing but protect yourself from other types (NSNumber, for example) is to check the type of the thing that you get back rather than comparing specifically against [NSNull null]:
if ([myString isKindOfClass:[NSString class]] && [myString length] > 1) { //...
In addition to the other answers, you could consider replacing NSNull instances with empty strings before parsing your API response into model objects. Similarly, you could traverse a mutable copy of the response dictionary and remove keys whose values contain NSNull.
Basically, do it up front when you get the response so that your code isn't littered with NSNull checks.
Another way to approach this is to use a Category:
#interface NSNull (Utilities)
- (NSString *)stringValue;
#end
#implementation NSNull (Utilities)
- (NSString *)stringValue
{
return nil;
}
#end
And then simply:
[myDictionary[#"key"] stringValue] // returns nil for NSNull values

Checking if a key in standardUserDefaults has been set or is NSNull

What is the correct way to check the contents of standardUserDefaults ?
If I print out what is stored in a key i get:
NSLog(#"logged_in_status : %#", [standardUserDefaults stringForKey:#"logged_in_status"]);
Output: logged_in_status : (null)
So it seems to be NSNull.
So I will add a check for that as follows:
if ([[standardUserDefaults objectForKey:#"logged_in_status"] isKindOfClass:[NSNull class]])
{
NSLog(#"YES");
}
else
{
NSLog(#"NO");
}
Output: NO
Why does this not resolve to the YES? Isn't it an NSNull?
I've been looking at this for a long time and can't see where the error is.
Could anybody kindly explain where I've gone wrong on this?
Thanks,
Code
When you do the key lookup initially, you're not getting back an instance of NSNull, but instead no result at all: in other words, nil, which isn't the same thing as NSNull. That typically means that no value has been set for that key in the user defaults yet. (You can see this if you look at it under the debugger while stepping through-- the "stringified" version of nil happens to be "(null)" when you print it to the log, which is partly what I think may be confusing here.)
(If this distinction is fuzzy for you, have a look at the answer to this question about the differences between the various forms of "null" you might encounter: What are the differences between nil, NULL and [NSNULL nil]?)
As #Francescu suggests in a comment, if you're trying to do a check for "has this value ever been set", it could look something like:
NSString * loggedInStatus = [standardUserDefaults stringForKey:#"logged_in_status"];
if (!loggedInStatus) {
NSLog(#"status not set");
} else {
NSLog(#"status: %#", loggedInStatus);
}
Just some additional info to the other answers: when you format a string including the %# format specifier, a nil value will format as "(null)" with parentheses. An instance of NSNull — the instance, since it's a singleton — formats as "<null>" with angle brackets.

Parse.com: How to properly check if a field is empty?

I ask this in the context of a iOS / Swift app:
When retrieving with a query an object from Parse, I used to check for empty fields by checking them against nil. if != nil.... then do this etc etc....
Apparently, this is not the proper way to do this, because even if a field is empty on Parse, it is NOT considered nil by swift.
So what to to check for to determine if a field is empty or not, and for the various Parse supported types: strings, Number, Array.....?
Edit: there are answers for objective-c that don't work in swift where unless value is a boolean you MUST compare it against nil (which cause issue here) or something else to see if it exists or not.
You would use whereKeyExists:
Checkout the Parse documentation
If you want to retrieve objects that have a particular key set, you can use whereKeyExists. Conversely, if you want to retrieve objects without a particular
key set, you can use whereKeyDoesNotExist.
// Finds objects that have the score set
[query whereKeyExists:#"score"];
Ok so here is what I found after some investigation:
A String field when it looks empty on parse explorer, in fact contains "". It is only when the field specifically has "undefined" in it that it is nil, which you can compare against with === and not ==. Not sure why, if someone knows....
Other fields than String, cannot contain "". They either contain a value or are undefined.
So if you need to know if a field is nil or contains no value, if it's a string compare it against == "" and === nil, and use === nil if it's not a string.
This is what I used to check whether a field containing a file is null. Since the value can be (undefined) or (null).
func isParseNull(obj : AnyObject!) -> Bool {
if obj == nil {
return true
}
if obj as NSObject == NSNull() {
return true
}
return false
}
I'm pretty sure the Parse documentation says !=nil however you could try
entity == ""
I would extend String class and do the following
extension String {
func isOnlyEmptySpacesAndNewLineCharacters() -> Bool {
return self.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()).length == 0
}
}
Here is my method, as I also struggled to check to see whether a string was empty in parse, and this seems to work fine.
- (void) nameCheck
{
//--------GET CURRENT USER-------//
PFUser *user = [PFUser currentUser];
//----------CHECK IF PARSE IS EMPTY OR TEXTFIELD IS EMPTY-----------//
if ([user[#"fullname"] isEqual: #""] || [fieldName.text isEqual:nil])
{
//-IF EMPTY, GIVE USER ANONYMOUS NAME-//
user[#"fullname"] = #"Anonymous User";
user[#"fullname_lower"] = #"anonymous user";
//------------------SAVE NEW NAME IN BACKGROUND----------------//
[user saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error)
{
if (error == nil)
{
NSLog(#"Saved Username");
}
}];
}
//--ELSE USER'S NAME EXISTS--//
else
{
//--LOAD USER METHOD--//
[self loadUser];
NSLog(#"User has username");
}
}

How to add string object in nsmutable array if some string is empty

arrdata=[[NSMutableArray alloc]initWithObjects:strname,strWeb,strAdd,strPhone,strrate, nil];
[arrAllData addObject:arrdata];
I fetched data from a webservice. in my condition if strweb has no value then it simply ignores other values like stradd,sphone and strrate. How can I solve this problem?
you can do like this in a simplest way.
if(strweb==nil)
{
strweb=#"null";
}
Note: pass null in <> bracket;
Try this code,
if(strWeb == nil){
strWeb = [NSString stringWithFormat:#"%#", [NSNull null]];
}
arrdata=[[NSMutableArray alloc]initWithObjects:strname,strWeb,strAdd,strPhone,strrate, nil];
[arrAllData addObject:arrdata];
When your any object nil while creation time of array then your array will be end with than object and remaining objects will discards. That why you need to check every object should not be nil according above code stuff then add it into array.
If strWeb is nil then your array structure will be
arrdata=[[NSMutableArray alloc]initWithObjects:strname,nil]; future object will discard.,strAdd,strPhone,strrate,
output of arrdata containg only one object strname
Other way,
Set any default value if your string is nil. for example,
if(strWeb == nil){
strWeb = #"This Value is discarded"; // It could be anything identifier for your purpose.
}
arrdata=[[NSMutableArray alloc]initWithObjects:strname,strWeb,strAdd,strPhone,strrate, nil];
[arrAllData addObject:arrdata];
While retrieving time you can match above string with value inside the object.
You use the initializer -initWithObjects:. As you know the object list is terminated with nil. If one of the references has the value nil, -initWithObjects: thinks that this is the terminator.
Check the references (i. e. strweb). If it is nil, assign a default value to it or do not encounter the variable in the list.

Resources