conditional operator without second attribute - objective-c

I have realized I'm not fully understand conditional operator when the second value is missing. Can anyone explain me (and paste equivalent with if-else statement) the following code:
if (self.root && [data isKindOfClass:[NSDictionary class]]) {
data = [data objectForKey:self.root] ? : data;
}

The ternary operator with no first element, e.g.
variable ?: anotherVariable
means the same as
(variable != nil) ? variable : anotherVariable
Here is some nice explanation about ternary operator in Objective-C.

u can do like this
to avoid confusion we take your sample code as
if (self.root && [data isKindOfClass:[NSDictionary class]]) {
myData = [data objectForKey:self.root] ? : data;
}
u can replace it with
if (self.root && [data isKindOfClass:[NSDictionary class]])
{
if([data objectForKey:self.root])
{
//if the condition is true (if data is non-nil)
myData = [data objectForKey:self.root]
}
else
{
//goes for false (if data is nil)
myData = data
}
}
for your case it goes like below
if (self.root && [data isKindOfClass:[NSDictionary class]]) {
myData = [data objectForKey:self.root] ? : data; //if the object found for key "self.root" then myData will hav the object for key "self.root" otherwise it "myData" hav "data"
}
lets take a simple example
//for example
BOOL aBoolValue = NO;
int num = (aBoolValue == YES) ? 100 : 50; //if aBoolValue is YES then num has 100 otherwise 50
//in the above example num contains 50

Related

Is it possible to enumerate strings as integers for a fast comparison? (Objective-C)

I need to enumerate 3 NSString as integers in a way that it would be easy to compare two numbers and find out which is the lower one. The 3 strings are:
#"verde" = 1
#"giallo" = 2
#"rosso" = 3
and it should be compared against an other integer in an if statement. Is this possible to do?
I'm not 100% sure I understand, but this might be what you want. Keep a dictionary of the string to integer mapping:
NSDictionary *stringMap = #{
#"verde": #(1),
#"giallo": #(2),
#"rosso": #(3)
};
and when it comes to the comparison, do:
NSString *s1 = #"verde";
NSString *s2 = #"rosso";
NSNumber *n1 = stringMap[s1];
NSNumber *n2 = stringMap[s2];
if (n1 && n2) {
NSComparisonResult result = [n1 compare n2];
if (result == NSOrderedAscending) {
// s1 < s2
} else if (result == NSOrderedDescending) {
// s1 > s2
} else {
// s1 == s2
}
}
You sound like in need for enum. Try this out:
Step 1 : Define an enum like this:
typedef NS_ENUM (NSInteger, MyStrings) {
Verde = 0,
Giallo,
Rosso
};
Step 2 : Define an enum type property like this:
#property (nonatomic, assign) MyStrings string;
Step 3 : Finally use it like this:
self.string = 2; // Setting property value
if (self.string < Verde) {
NSLog(#"Small Value");
} else {
NSLog(#"Big Value");
}

Checking if two loops returns a value

I want to check if the two for loops returns a match, if they do nothing happens but if they don't I want a message to be printed out saying something like "A match could not be found". Something like this:
if (loop1 == 0 && loop2 == 0) {
NSLog(#"A match could not be found, please check your spelling");
};
My question is therefore, how can I describe the loops so that I can check the value they give?
Here are the loops:
for (SMADoc *aSearch in docs) {
if ([search isEqualToString:[aSearch leadAuthour]]) {
//Open the file that is represented by UrlToDoc for that specific object
[[NSWorkspace sharedWorkspace] openFile:[aSearch urlToDoc]];
}
}
} else {
//The string starts with a number and should be converted to an int and then the array of the numbers should be searched through
int number = atoi(searchC);
NSNumber *sNumber = [NSNumber numberWithInt:number];
for (SMADoc *nSearch in docs) {
if ([sNumber isEqualToNumber:[nSearch docNumber]]) {
[[NSWorkspace sharedWorkspace] openFile:[nSearch urlToDoc]];
}
}
}
Thanks in advance!
As your custom class is KVC compliant you could perform the check simultaneously with NSPredicate without any loop.
The expression means: if docs contains an object whose docNumber is number or leadAuthour is search, skip the error message
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"docNumber == %i || leadAuthour == %#", number, search];
if [[docs filteredArrayUsingPredicate:predicate] count] == 0 {
NSLog(#"A match could not be found, please check your spelling");
}
I solved it! I started by declaring two ints, one for each loop, and then checked if a match was NOT found for each iteration, i.e:
![search isEqualToString:[aSearch leadAuthour]]
If this was true, the int was increased by one. Then, after the array was iterated through, if the int is equal to the number of objects in the array, I then knew that none of the objects matched and I could print out the "A match could not be found, please check your spelling"-message. This is how it looked like in code:
int i = 0;
int j = 0;
for (SMADoc *aSearch in docs) {
if ([search isEqualToString:[aSearch leadAuthour]]) {
//Open the file that is represented by UrlToDoc for that specific object
[[NSWorkspace sharedWorkspace] openFile:[aSearch urlToDoc]];
}
if(![search isEqualToString:[aSearch leadAuthour]]){
i++;
}
if(i == [docs count]) {
NSLog(#"A match could not be found, please check your spelling");
}
}
} else {
//The string starts with a number and should be converted to an int and then the array of the numbers should be searched through
int number = atoi(searchC);
NSNumber *sNumber = [NSNumber numberWithInt:number];
for (SMADoc *nSearch in docs) {
if ([sNumber isEqualToNumber:[nSearch docNumber]]) {
[[NSWorkspace sharedWorkspace] openFile:[nSearch urlToDoc]];
}
if(![search isEqualToString:[aSearch docNumber]]){
j++;
}
if(j == [docs count]) {
NSLog(#"A match could not be found, please check your spelling");
}
}
I don't know if it's allowed to answer your own question, but my intention with this was to provide an answer for someone who might be asking the same question.

Checking to see if ObjectForKey exists [duplicate]

Most of the examples I found on the net write this:
if(x != nil)
// ...
Is there any problems with this?
if(x)
// ...
I tried both in a simple program and couldn't found any difference.
In Objective-C, nil is defined as a value called __DARWIN_NULL, which essentially evaluates to 0 or false in if-statements. Therefore, writing
if (x == nil) is the same as writing if (!x) and writing if (x != nil) is equal to if (x) (since comparing to false creates a negation, and comparing to true keeps the condition the same).
You can write your code either way, and it really depends on which you think is more readable. I find if (x) to make more sense, but it depends on your style.
It's like comparing if (someCondition == true) versus if (someCondition).
It all depends on you, and who's going to be reading the code.
Edit: As Yuji correctly mentions, since Objective-C is a superset of C, any condition that evaluates to a value other than 0 is considered to be true, and therefore, if someCondition in the example above were to evaluate to an integer value of, say, -1, comparing it to true would result in false, and the if-statement would not be evaluated. Something to be aware of.
Both
if (x != nil)
and
if ( x )
are equivalent, so pick the variant that in your opinion makes your code more readable for you (and others who will read and support your code)
Both are the same and this is a style question and it boils down to whether you prefer:
if (something) { ... }
versus
if (something != nothing) { ... }
I have always found #1 more clear but #2 is used extensively in documentation and hence the field so it is better to both know both forms and adapt to what a project uses and be stylistically consistent.
The best and safe way to check nil is
Make a common method, and add all these null :
+ (NSString *)trimWhiteSpaceAndNewLine:(NSString *)string {
NSString *stringSource = [NSString stringWithFormat:#"%#",string];
if ([stringSource isEqualToString:#"(null)"]) {
stringSource = #"";
return stringSource;
}
if ([stringSource isEqualToString:#"<null>"]) {
stringSource = #"";
return stringSource;
}
if ([stringSource isEqualToString:#"<nil>"]) {
stringSource = #"";
return stringSource;
}
if ([stringSource isKindOfClass:[NSNull class]]) {
stringSource = #"";
return stringSource;
}
if ([stringSource isEqualToString:#""]) {
stringSource = #"";
return stringSource;
}
if (stringSource == nil) {
stringSource = #"";
return stringSource;
}
NSString *stringFinal = [stringSource stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
return stringFinal;
}
And check
NSString *strUuid = [Common trimWhiteSpaceAndNewLine:[dict valueForKeyPath:#"detail.uuid"]];
if (![strUuid isEqualToString:#""]) {
// do your stuff
}

How to access array fields in sudzc.com SOAP result?

Sorry to perhaps ask stupid questions, but I'm still having issues with Objective-C syntax.
So, I've got this SOAP response from my sudzc.com generated code. It should contain a SQL SELECT result with veh_id and version as columns.
What I get as a response object is a NSMutableArray,
NSMutableArray* soapArray = (NSMutableArray*)value;
so I walk through it:
unsigned count = [soapArray count];
while (count--) {
id myobj = [soapArray objectAtIndex:count];
NSLog(#"myobj: %#", myobj);
}
What I get as a printout is something like:
myobj: {
item = {
key = version;
value = 1;
};
for each row of the SQL result. If this is a printout of the array element, why is there only the version column and not also the veh_id column?
How do I access the value for the key on the object myobj of type id? Do I have to cast it first?
That's the XML String returned from the Zend Soap-Server:
<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://www.[myurl].com/soap" xmlns:ns2="http://xml.apache.org/xml-soap" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><ns1:getActiveVehiclesResponse><return SOAP-ENC:arrayType="ns2:Map[23]" xsi:type="SOAP-ENC:Array"><item xsi:type="ns2:Map"><item><key xsi:type="xsd:string">veh_id</key><value xsi:type="xsd:string">1</value></item><item><key xsi:type="xsd:string">version</key><value xsi:type="xsd:string">1</value></item></item><item xsi:type="ns2:Map"><item><key xsi:type="xsd:string">veh_id</key><value xsi:type="xsd:string">3</value></item><item><key xsi:type="xsd:string">version</key><value xsi:type="xsd:string">1</value></item></item><item xsi:type="ns2:Map"><item><key xsi:type="xsd:string">veh_id</key><value xsi:type="xsd:string">4</value></item><item><key xsi:type="xsd:string">version</key><value xsi:type="xsd:string">1</value></item></item></return></ns1:getActiveVehiclesResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>
No.. You don't need to cast it, since it shows all the data fetched, I am facing problem that the handler method value (of id type) returns first element only.
check following code:
...
request = [service myServiceCall:self action:#selector(myHandlerMethod:) param:param1];
...
}
-(void) myHandlerMethod:(id)value{
NSString *xmlString = [[NSString alloc] initWithData:request.receivedData encoding:NSUTF8StringEncoding];
// now if the "value" returned is type as some array of some object,then any arrays don't handle serialization of all the elements of the array it holds. The following code prints just outer tag. (e.g. )
NSLog("%#",xmlString);
}
Finally found the solution!
The problem lies within the deserializeAsDictionary function.
Since my Soap xml string is structured to have each database column as item - key - value - key - value etc, it adds each column under the key "item" and thus the deserializeAsDictionary function overwrites in the line
[d setObject:v forKey:[child name]]
the already added objects. In a first shot, I have added a column iterator and now call the columns "item1, item2,.." (further optimization might be necessary):
// Deserializes the element in a dictionary.
+(id)deserializeAsDictionary:(CXMLNode*)element {
NSLog(#"deserializeAsDictionary = %#, children: %d", element.stringValue, [element childCount]);
if([element childCount] == 1) {
CXMLNode* child = [[element children] objectAtIndex:0];
if([child kind] == CXMLTextKind) {
NSLog(#"child %# added", [child stringValue]);
return [[[element children] objectAtIndex:0] stringValue];
}
}
NSMutableDictionary* d = [NSMutableDictionary dictionary];
NSInteger i = 1;
NSString *objKey;
for(CXMLNode* child in [element children]) {
id v = [Soap deserialize:child];
if(v == nil) {
v = [NSNull null];
} else {
if([[child name] isEqualToString:#"(null)"]) {
objKey = [NSString stringWithFormat:#"%#",[child stringValue]];
} else if([[child name] isEqualToString:#"key"] || [[child name] isEqualToString:#"value"]) {
objKey = [NSString stringWithFormat:#"%#",[child name]];
} else {
objKey = [NSString stringWithFormat:#"%#%d",[child name],i++];
}
}
[d setObject:v forKey:objKey];
NSLog(#"child %# added", objKey);
}
return d;
}
The result array now looks like:
},
{
item1 = {
key = "veh_id";
value = 29;
};
item2 = {
key = version;
value = 1;
};
}

How to check if an NSDictionary or NSMutableDictionary contains a key?

I need to check if an dict has a key or not. How?
objectForKey will return nil if a key doesn't exist.
if ([[dictionary allKeys] containsObject:key]) {
// contains key
}
or
if ([dictionary objectForKey:key]) {
// contains object
}
More recent versions of Objective-C and Clang have a modern syntax for this:
if (myDictionary[myKey]) {
}
You do not have to check for equality with nil, because only non-nil Objective-C objects can be stored in dictionaries(or arrays). And all Objective-C objects are truthy values. Even #NO, #0, and [NSNull null] evaluate as true.
Edit: Swift is now a thing.
For Swift you would try something like the following
if let value = myDictionary[myKey] {
}
This syntax will only execute the if block if myKey is in the dict and if it is then the value is stored in the value variable. Note that this works for even falsey values like 0.
if ([mydict objectForKey:#"mykey"]) {
// key exists.
}
else
{
// ...
}
When using JSON dictionaries:
#define isNull(value) value == nil || [value isKindOfClass:[NSNull class]]
if( isNull( dict[#"my_key"] ) )
{
// do stuff
}
I like Fernandes' answer even though you ask for the obj twice.
This should also do (more or less the same as Martin's A).
id obj;
if ((obj=[dict objectForKey:#"blah"])) {
// use obj
} else {
// Do something else like creating the obj and add the kv pair to the dict
}
Martin's and this answer both work on iPad2 iOS 5.0.1 9A405
One very nasty gotcha which just wasted a bit of my time debugging - you may find yourself prompted by auto-complete to try using doesContain which seems to work.
Except, doesContain uses an id comparison instead of the hash comparison used by objectForKey so if you have a dictionary with string keys it will return NO to a doesContain.
NSMutableDictionary* keysByName = [[NSMutableDictionary alloc] init];
keysByName[#"fred"] = #1;
NSString* test = #"fred";
if ([keysByName objectForKey:test] != nil)
NSLog(#"\nit works for key lookups"); // OK
else
NSLog(#"\nsod it");
if (keysByName[test] != nil)
NSLog(#"\nit works for key lookups using indexed syntax"); // OK
else
NSLog(#"\nsod it");
if ([keysByName doesContain:#"fred"])
NSLog(#"\n doesContain works literally");
else
NSLog(#"\nsod it"); // this one fails because of id comparison used by doesContain
Using Swift, it would be:
if myDic[KEY] != nil {
// key exists
}
Yes. This kind of errors are very common and lead to app crash. So I use to add NSDictionary in each project as below:
//.h file code :
#interface NSDictionary (AppDictionary)
- (id)objectForKeyNotNull : (id)key;
#end
//.m file code is as below
#import "NSDictionary+WKDictionary.h"
#implementation NSDictionary (WKDictionary)
- (id)objectForKeyNotNull:(id)key {
id object = [self objectForKey:key];
if (object == [NSNull null])
return nil;
return object;
}
#end
In code you can use as below:
NSStrting *testString = [dict objectForKeyNotNull:#"blah"];
For checking existence of key in NSDictionary:
if([dictionary objectForKey:#"Replace your key here"] != nil)
NSLog(#"Key Exists");
else
NSLog(#"Key not Exists");
Because nil cannot be stored in Foundation data structures NSNull is sometimes to represent a nil. Because NSNull is a singleton object you can check to see if NSNull is the value stored in dictionary by using direct pointer comparison:
if ((NSNull *)[user objectForKey:#"myKey"] == [NSNull null]) { }
Solution for swift 4.2
So, if you just want to answer the question whether the dictionary contains the key, ask:
let keyExists = dict[key] != nil
If you want the value and you know the dictionary contains the key, say:
let val = dict[key]!
But if, as usually happens, you don't know it contains the key - you want to fetch it and use it, but only if it exists - then use something like if let:
if let val = dict[key] {
// now val is not nil and the Optional has been unwrapped, so use it
}
I'd suggest you store the result of the lookup in a temp variable, test if the temp variable is nil and then use it. That way you don't look the same object up twice:
id obj = [dict objectForKey:#"blah"];
if (obj) {
// use obj
} else {
// Do something else
}
if ([MyDictionary objectForKey:MyKey]) {
// "Key Exist"
}
As Adirael suggested objectForKey to check key existance but When you call objectForKeyin nullable dictionary, app gets crashed so I fixed this from following way.
- (instancetype)initWithDictionary:(NSDictionary*)dictionary {
id object = dictionary;
if (dictionary && (object != [NSNull null])) {
self.name = [dictionary objectForKey:#"name"];
self.age = [dictionary objectForKey:#"age"];
}
return self;
}
if ( [dictionary[#"data"][#"action"] isKindOfClass:NSNull.class ] ){
//do something if doesn't exist
}
This is for nested dictionary structure