Comparing NSDecimalNumber won't work? - objective-c

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

Related

NSDictionary returning same value for different keys

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)];

I'm using NSDecimalNumber in a method that works out a total price and sometimes it returns only one number after decimal when two are intended

I've have a method that loops through my core data fetched objects array and uses the price of each item and the quantity to work out the total price. It seems to work most of the time returning for e.g. 23.44, 3.65 but I've noticed that sometimes it will return for example 63.1 like below.
Here is my method:
+ (NSDecimalNumber *)totalPriceOfItems:(NSManagedObjectContext *)managedObjectContext
{
NSError *error = nil;
NSDecimalNumber *totalPrice = [[NSDecimalNumber alloc] initWithInt:0];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"BagItem"];
// Get fetched objects and store in NSArray
NSArray *fetchedObjects = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
for (BagItem *bagItem in fetchedObjects) {
NSDecimalNumber *price = [[NSDecimalNumber alloc] initWithDecimal:[[bagItem price] decimalValue]];
NSDecimalNumber *quantity = [[NSDecimalNumber alloc] initWithInt:[[bagItem quantity] intValue] + 1];
NSDecimalNumber *priceFromQuantity = [price decimalNumberByMultiplyingBy:quantity];
totalPrice = [totalPrice decimalNumberByAdding:priceFromQuantity];
NSLog(#"total: %#", totalPrice);
}
return totalPrice;
}
Am I doing something wrong here?
Haven't had much experience using NSDecimalNumber but hopefully someone can help me figure this out.
Thanks for your time.
This isn't an NSDecimalNumber issue. Instead, the problem lies in the NSNumberFormatter that you're using. Configure it to use minimumFractionDigits = 2.
You can simply achieve that with the help of String Format Specifiers something like:
NSLog(#"total: %.2f", [totalPrice floatValue]);
or
[NSString stringWithFormat:#"%.2f", [totalPrice floatValue]]
%.2f which simply means two decimal places after the "."

Objective C: comparing dictionary contents

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");
}

changing a string to double returning one

I have stored a value 1/129600.0 in a plist as a string.
I am able to retrieve it as a string but when i am trying to convert it as a double i am getting it as 1.0.I have also tried CFString
NSString *value = [[self array]objectAtIndex:m];
double a = [value doubleValue];
NSLog(#"%#",value);
NSLog(#"%f",a);
and in log the returned values are
1/129600.0 and 1.0
This code works fine, I tried it in xCode:
NSString *equation = [[self array]objectAtIndex:m];
NSExpression *result = [NSExpression expressionWithFormat:equation];
NSNumber *a = [result expressionValueWithObject:nil context: nil];
NSLog(#"%#",result);
NSLog(#"%.10f",[a doubleValue]);
I guess 1/129600.0 is not a valid number.
Try to create an expression and create an NSNumber from it:
NSString *equation = [[self array]objectAtIndex:m];
NSNumber *a = [[NSExpression expressionWithFormat:equation] expressionValueWithObject:nil context:nil];
double a = [result doubleValue];
NSLog(#"%f", a);
1/129600.0 is not a valid representation for a number in most programming languages, including ObjC. You need to parse the string and interpret it yourself.
Try this
NSString *value = [[self array]objectAtIndex:m];
NSArray *arr = [value componentsSeparatedByString:#"/"];
double a;
if ([arr count] == 2)
{
a = [arr objectAtIndex:0]/[arr objectAtIndex:1];
}
NSLog(#"%#",value);
NSLog(#"%f",a);

NSPredicate for calculated field with NSDecimalNumber

I want to filter a calculated field (binary expression in terms of Apple documentation) in Core Data with a NSDecimalNumber value.
The entity has two attributes: field1 and field2, both of type Decimal
The predicate is:
NSDecimalNumber *number = ...;
NSString *predicateString = #"(field1 + field2) <= %#";
NSArray *arguments = [NSArray arrayWithObjects:number, nil];
[NSPredicate predicateWithFormat:predicateString argumentArray:arguments];
But this doesn't work. It gives nothing back.
When i filter each Attribute alone then it works. For example:
NSString *predicateString = #"field1 <= %#"; //ok
NSString *predicateString = #"field2 <= %#"; //ok
What's wrong?