Objective C syntax issue related to parameter not getting right data - ios

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.

Related

Concatenate Strings for Dictionary:syntax error

The following code to conditionally concatenate strings for a dictionary seems to work up to the point where I try to place the concatenated result in the dictionary. Can anyone see the error?
NSDictionary *jsonDictionary;
NSString* dictString = #"#\"first\":first,#\"last"
NSString *dictString2=dictString;
if (date.length>0&&![date isKindOfClass:[NSNull class]]) {
//only include this key value pair if the value is not missing
dictString2 = [NSString stringWithFormat:#"%#%s", dictString, "#\"date\":date"];
}
jsonDictionary = #{dictString2}; //syntax error. Says expected colon but that does not fix anything
The syntax for creating an NSDictionary using object literals is:
dictionary = #{key:value}
(and optionally, it can contain multiple key/value pairs separated by commas, but never mind that right now.)
Where "key" and "value" are both NSObjects.
Your line that is throwing the error only contains 1 thing. The contents of a the string in dictString2 has nothing to do with it.
It looks to me like you are trying to build a JSON string manually. Don't do that. Use NSJSONSerialization. That class has a method dataWithJSONObject that takes an NSObject as input and returns NSData containing the JSON string. That's how you should be creating JSON output.
Creating an NSDictionary with values that may be null:
NSDictionary *dict = #{
#"key" : value ?: [NSNull null],
};
When serializing a dictionary, NSNulls are translated to null in the JSON.
If you want to exclude such keys completely, instead of having them with a null value, you'll have to do more work. The simplest is to use an NSMutableDictionary and test each value before adding it.

Assigning nil to an element on NSMutableDictionary in Objective-C removes that element, is that a sanctioned feature or bug?

I have a NSMutableDictionary.
NSMutableDictionary * dict = #{
#"0" : #"car",
#"1" : #"ball",
#"2" : #"plane",
}
At one point, by error, I was assigning a nil to to an element on a dictionary. For example:
dict[#"1"] = nil;
for my surprise, instead of crash, the element "1" is being deleted.
Is this something recent? a sanctioned feature or a bug? I wonder if this is a feature, because I always used something like
[dict removeObjectForKey:#"1"];
To remove objects from dictionaries.
I never knew it was possible. Perhaps Apple is making Objective-C similar to Swift.
I just verified the behavior in Swift 2.0.
var dict: NSMutableDictionary = [ "0" : "car", "1" : "ball", "2" : "plane" ];
dict["1"] = nil
print("\(dict)")
It must to be a bug because it contradicts the documentation.
From NSMutableDictionary Class Reference:
- setObject:forKeyedSubscript:
Adds a given key-value pair to the dictionary.
Declaration
OBJECTIVE-C
- (void)setObject:(ObjectType)object
forKeyedSubscript:(id)aKey
Parameters
object
The value for aKey. A strong reference to the object is maintained by the dictionary.
IMPORTANT
Raises an NSInvalidArgumentException if anObject is nil. If you need to represent a nil value in the dictionary, use NSNull.
aKey
The key for value. The key is copied (using copyWithZone:; keys must conform to the NSCopying protocol). If aKey already exists in the dictionary, anObject takes its place.
IMPORTANT
Raises an NSInvalidArgumentException if aKey is nil.
UPDATE: 2016-04-21
Apple has updated it's documentation! passing a nil value can be used to delete a key.
object
The value for aKey. A strong reference to the object is maintained by the dictionary.
Passing nil will cause any object corresponding to aKey to be removed from the dictionary.
There are different APIs to add an object to a mutable dictionary and they behave differently when you pass nil:
setObject:forKeyedSubscript: (a.k.a dict[key] = nil) and setValue:forKey: accept nil and in that case they will remove the object associated corresponding to that key.
setObject:forKey: will raise an exception if nil is passed
All this is documented in https://developer.apple.com/documentation/foundation/nsmutabledictionary

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

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.

Kind of null variable IOS

i am actually debugging my iOS Application: i want to test if a variable is null or not:
Stupid question huh !
if (var !=nil) { doSomeWork ; }
So if the variable var is equal to nil and we want to print this result in the debugger area we will have something like that:
2012-10-12 21:33:01.553 Application's Name [892:13d03] (null)
This is cool, but indeed when i try to print the variable content in the debugger area, it has been showing :
2012-10-12 21:33:01.553 Application's Name [892:13d03] < null >
Can you tell me guys what is the difference between this two kinds of null, and how can i test if the second one is equal to nil.
Thanks in advance
The second output, <null>, comes from the NSNull singleton. This is a class called NSNull that has a class method +null that returns the same singleton instance of NSNull every time. The primary purpose of this class it to be able to act as a stand-in for nil in places where you can't put nil, such as in collections. For example, JSON libraries typically return NSNull when the JSON includes null.
You can test for this simply by asking if it's == to [NSNull null] (since it's a singleton), or possibly if [obj isKindOfClass:[NSNull null]]. You could use [obj isEqual:[NSNull null]] if you like. You could even ask if it's == kCFNull if you want, since CFNull and NSNull are toll-free bridged. Whatever style you want is up to you.
NSNull it is class, nil is not. So if you are comparing nil with something you should use "==", if NSNull then -> if ([var isEqual:[NSNull null]]) { ....}

Resources