I have a dictionary declared, like this,
NSString *responseString = [request responseString];
responseDict = [responseString JSONValue];
for (id key in responseDict){
NSLog(#"%# : %#", key, [responseDict objectForKey:key]);
}
Result :
013-01-22 00:14:02.323 PromoTest[2352:c07] A : 0
2013-01-22 00:14:02.325 PromoTest[2352:c07] B : 1
2013-01-22 00:14:02.325 PromoTest[2352:c07] C : 0
now, I want to compare the value and do some operation on it. I presumed the value for a key is of type NSString and compared it to my constant NSString, like this,
NSString *myString1 = #"0";
NSString *myString2 = [responseDict objectForKey:#"A"];
NSLog(#"%d", (myString1 == myString2)); //1
NSLog(#"%d", [myString1 isEqualToString:myString2]); //1
Result:
2013-01-22 00:19:12.966 PromoTest[2423:c07] 0
2013-01-22 00:19:12.966 PromoTest[2423:c07] 0
Where am i going wrong?? Is my comparison wrong? How do I go about correctly comparing the content??
The data is being received as response data from a web service. I am just converting the data into a dictionary for easily using it. The web service returns a JSON object,
{"A":0,"B":1,"C":0}
NSDictionary method isEqualToDictionary can be used to compare 2 dictionaries
Returns a Boolean value that indicates whether the contents of the
receiving dictionary are equal to the contents of another given
dictionary.
For example:
[myDictionary isEqualToDictionary:expectedDictionary]
The only reasonable explanation is that [responseDict objectForKey:#"A"] is not returning a NSString.
You are probably getting a NSNumber back, therefore the comparison fails.
If that's the case you need to get a NSString from the NSNumber before comparing it against your constant. You can do it by
NSString * myString2 = [[responseDict objectForKey:#"A"] stringValue];
Also never use == to compare NSStrings instances. Stick with isEqualToString and you'll be good.
Instead of comparing strings you could also compare number object. here including with a check, if the returned object is a NSNumber, if not, try as string:
if([responseDict[#"A"] isKindOfClass:[NSNumber class]]){
NSNumber *myNumber1 = #0;
NSNumber *myNumber2 = [responseDict objectForKey:#"A"];
NSLog("Same number: %#",[myNumber1 isEqualToNumber:myNumber2] ? #"YES" : #"NO");
} else if([responseDict[#"A"] isKindOfClass:[NSString class]]){
NSString *myString1 = #"0";
NSString *myString2 = [responseDict objectForKey:#"A"];
NSLog("Same string: %#",[myString1 isEqualToString:myString2] ? #"YES" : #"NO");
}
Related
I have some Obj-C code that uses NSNumbers as keys in a dictionary. I'd found a bug that I tracked down to some very strange behavior where if the dictionary is accessed using NSDecimalNumber (a subclass of NSNumber) it would always return the same element. Here's a small program that exhibits the behavior and the NSLogs output the problem:
#define LONGNUMBER1 5846235266280328403
#define LONGNUMBER2 5846235266280328404
- (void) wtfD00d {
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
NSNumber *key1 = [NSNumber numberWithLongLong:LONGNUMBER1];
NSNumber *key2 = [NSNumber numberWithLongLong:LONGNUMBER2];
dict[key1] = #"ONE";
dict[key2] = #"TWO";
NSNumber *decimalKey1 = [NSDecimalNumber numberWithLongLong:LONGNUMBER1];
NSNumber *decimalKey2 = [NSDecimalNumber numberWithLongLong:LONGNUMBER2];
NSString *value1 = dict[decimalKey1];
NSString *value2 = dict[decimalKey2];
NSLog(#"Number of entries in dictionary = %lu", (unsigned long)dict.count); // 2
NSLog(#"%#", dict); // 5846235266280328403 = ONE
// 5846235266280328404 = TWO
NSLog(#"Value1 = %#, Value 2 = %#", value1, value2); // Value1 = ONE, Value 2 = ONE
NSLog(#"key2 = decimalKey2: %#", [key2 isEqual:decimalKey2] ? #"True" : #"False"); // key2 isEqual decimalKey2: True
NSLog(#"decimalKey1 = decimalKey2: %#", [decimalKey1 isEqual:decimalKey2] ? #"True" : #"False"); // decimalKey1 isEqual decimalKey2: False
}
Notice that the 3rd log line shows that value1 and value2 are the same. WHY does this happen?
This came up because we have a few fields in CoreData with type Decimal and they come out of CoreData as NSNumber. We found that we had to play games to get around this strange behavior and I don't understand why it happens in the 1st place. I'd love any insight anyone can offer as to why the failed lookups.
I think that when NSNumber and NSDecimalNumber are compared with each other, they are using doubleValue for comparison.
You can report bug in apple for that
I can suggest only to avoid NSNumber<->NSDecimalNumber comparison and use here:
NSString *value1 = dict[#(decimalKey1.longLongValue)];
NSString *value2 = dict[#(decimalKey2.longLongValue)];
What is the difference of notificationIdToCancle1 and notificationIdToCancle2 in the code below:
NSDictionary* parameters = (NSDictionary* )parametersObject;
if (parameters != nil) {
NSString* notificationIdToCancle1 = (NSString* )[parameters objectForKey:#"id"];
NSString *notificationIdToCancle2 = [NSString stringWithFormat:#"%#",[parameters valueForKey:#"id"]];
}
Shouldn't both contain the same value?
NSString* notificationIdToCancle1 = (NSString* )[parameters objectForKey:#"id"];
This line is grabbing the object in the dictionary, casting it to an NSString whether it is or isn't.
[NSString* stringWithFormat:#"%#",[parameters valueForKey:#"id"]];
This line, I think you have a mistake, you probably don't want the first '*'. You also probably want to call 'objectForKey:' rather than 'valueForKey:'. objectForKey: will return the entry in the dictionary, while valueForKey: will use Key Value Coding to return a value.
So:
[NSString stringWithFormat:#"%#",[parameters objectForKey:#"id"]];
This takes the object in the dictionary, runs 'description' on it which returns an NSString instance. So you definitely get an NSString instance out of it.
I have an NSString that returns a list of values like this:
test_1=value_1
test/2=value_2
test3=value_3 value_4
test_4=value_5/value_6
...
More realistic result values:
inameX=vlan2
hname=server
lanipaddr=192.168.1.1
lannetmask=255.255.255.0
islan=0
islwan=0
dhcplease=604800
dhcplease_1=302400
ct_tcp_timeout=0 1200 40 30 60 60 5 30 15 0
ct_timeout=10 10
ct_udp_timeout=25 60
ctf_disable=1
ddnsx0=
cifs2=0<\\192.168.1.5
and so on...
If I do:
for (id key in dict) {
NSLog(#"key: %#, value: %#", [dict objectForKey:key], key);
}
it outputs:
key: inameX, value: vlan2
key: hname value: server
key: lanipaddr value: 192.168.1.1
key: lannetmask value: 255.255.255.0
This list is stored in one NSString *result. Not sure if I should put it in an array for this but I need to be able to call a function or command that will return a specific value_X based on the argument to match the variable. For example, get value of test_1 variable then it would return value_1. Or get test_4 then it would return value_5/value_6
Any idea how I can do that?
I appreciate your help. Thanks!
You probably want the method in NSString called componentsSeparatedByCharactersInSet: to split up that one string into an array. Since your values are separated by '=' and new line characters ('\n'), you want the set to include those two characters:
NSArray *strings = [NSString componentsSeparatedByCharactersInSet:
[NSCharacterSet characterSetWithCharactersInString:#"=\n"]];
And then you can make this into a dictionary with NSDictoinary's dictionaryWithObjects: AndKeys: But first, you need to split that array into two arrays; one with objects, one with keys:
NSMutableArray *keys = [NSMutableArray new];
NSMutableArray *values = [NSMutableArray new];
for (int i = 0; i < strings.count; i++) {
if (i % 2 == 0) { // if i is even
[keys addObject:strings[i]];
}
else {
[values addObject:strings[i]];
}
}
Then you put them into an NSDictonary
NSDictionary *dict = [NSDictionary dictionaryWithObjects:values forKeys:keys];
NSLog(#"%#", dict[#"test_1"]) // This should print out 'value_1'
Hope that helps!
Use an NSDicationary. NSDictionaries are key value stores. In other words, there are a list of keys. Each key is unique. Each key has an associated value. The value can be any data type and the key has to conform to the NSCopying protocol (typically an NSString). If you try to access the value for a key that doesn't exist in your NSDictionary, the return value will be nil.
//create the dictionary and populate it
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setObject:#"value_1" forKey:#"key_1"];
[dict setObject:#"value_2" forKey:#"key_2"];
[dict setObject:#"value_3" forKey:#"key_3"];
[dict setObject:#"value_4" forKey:#"key_4"];
NSString *stringInput = [self getStringInput];//however you find out your input
//find your string value based on the key passed in
NSString *strValue = [dict objectForKey:stringInput];
You can use a NSScanner to make this work.
Scan for the string for which you want the value, and then scan the string until you encounter \n and then use it for your requirement.
NSScanner *scan =[NSScanner scannerWithString:theString];
[scan scanString:keyString inToString:nil];
[scan setScanLocation:[scan scanLocation]+1];
[scan scanString:#"\n" inToString:requiredString];
So requiredString is the string which you want.
For some reason, the comparing logic isn't working correctly... it wont compare two NSDecimalNumber objects. Sometimes it works, sometimes it doesn't. Really weird. The if statement works on some compilations, and sometimes not. Is this the right way of doing it?
The data is from a json file which is a 2 point decimal number which looks like this: 63.32
Why isn't this working correctly?
NSError * error;
NSDictionary * json = [NSJSONSerialization JSONObjectWithData:responceData options:kNilOptions error:error];
NSArray * latestPrice = [json objectForKey:#"data"];
NSLog(#"Latest price %#", latestPrice);
NSNumber * value = [(NSDictionary*)[latestPrice objectForKey:#"last_offer"] objectForKey:#"display"];
NSString * val = [[NSString alloc] initWithFormat:#"%#", value];
NSString * valFinal = [val stringByTrimmingCharactersInSet:[NSCharacterSet symbolCharacterSet]];
NSDecimalNumber *number = [NSDecimalNumber decimalNumberWithString:valFinal];
NSLog(#"%#", number);
NSString * val2 = [[NSString alloc] initWithString:#"44.14"];
NSDecimalNumber *number2 = [NSDecimalNumber decimalNumberWithString:val2];
if(number2 >= number){
NSLog(#"ds");
}
I need to compare the json value with a local value with the same decimal points.
NSDecimalNumber is an object. You tried to compare memory addresses.
Use compare: instance method of NSDecimalNumber.
if ([number compare:number2] == NSOrderedAscending)
NSDecimalNumber Class Reference
I am trying to split the string into parts and insert into a table how should i do it?
I got an error for splitting of the array which is: -[__NSArrayI componentsSeparatedByString:]: unrecognized selector sent to instance 0x7a421e0
NSArray *BusRoute = alightDesc;
int i;
int count = [BusRoute count];
for (i = 0; i < count; i++)
{
NSDictionary *dic = [BusRoute objectAtIndex: i];
NSDictionary *STEPS = [dic valueForKey:#"STEPS"];
NSString *AlightDesc = [STEPS valueForKey:#"AlightDesc"];
NSLog(#"AlightDesc = %#", AlightDesc);
NSArray *aDescArray = [AlightDesc componentsSeparatedByString:#","];
NSLog(#"aDescArray = %#", aDescArray);
}
This is the string which I'm splitting, i got it from the NSLog
AlightDesc = (
"Block1",
"Block2",
"Block3"
)
please help I'm stuck thanks.
Objective C is not a strongly typed language. All you know for sure about [STEPS valueForKey:#"AlightDesc"] is that it will return an object (of type id). When you wrote NSString *AlightDesc = [STEPS valueForKey:#"AlightDesc"] the compiler did not complain because NSString * is a valid object type. Unfortunately there is a logic error in your code so that what was actually stored under the key #"AlightDesc" is an NSArray. As others have mentioned, NSArray does not respond to componentsSeparatedByString: so you get an error at runtime.
The easy fix for this is to correct your logic: Either store an NSString in the first place or treat what you get out as an NSArray. As #janusfidel mentioned you can use an NSArray perfectly well in a table by using objectAtIndex: to get the string for the entry you want.
In some more complicated cases you may not know what you will be getting out of a dictionary for a particular key. In that case in Objective C you can just ask the object:
id anObject = [STEPS valueForKey:#"AlightDesc"];
if ([anObject isKindOfClass:[NSString class]]) {
NSString *aString = (NSString *)anObject;
// Treat as a string ...
} else if ([anObject isKindOfClass:[NSString class]]) {
// Object is an array ...
Your NSString *AlightDesc should look like this
NSString *AlightDesc = "Block1,Block2,Block3";
NSArray *aDescArray = [AlightDesc componentsSeparatedByString:#","];
If your string is what you say it is
AlightDesc = ("Block1","Block2","Block3");
then your string is the problem because it's already broken up.