NSDecimalNumber question for core data and iPhone
Asked Answered
I

2

5

I'm fairly new to core data and iphone programming. Maybe this is an obvious answer, so if anyone can point me to a tutorial or other resource, it's greatly appreciated! I have a core data entity that is a decimal type as it's dealing with currency, and everything I have read says to use NSDecimalNumber when dealing with currency. That being said, I cannot for the life of me figure out how to set the value when inserting a new object. Here is what I have

NSManagedObjectContext *moc = [self.fetchedResultsController managedObjectContext];
Envelope *envelope = [NSEntityDescription insertNewObjectForEntityForName:@"Envelope"
                                                inManagedObjectContext:moc];
[envelope setValue:@"Envelope 1" forKey:@"name"];
NSDecimalNumber *budgetNumber = [NSDecimalNumber decimalNumberWithDecimal:1.00];
[envelope setValue:budgetNumber forKey:@"budget"];

What am I doing wrong here? thanks in advance!

Insect answered 6/3, 2011 at 20:9 Comment(4)
What problem are you having? Compile errors? Crash? More info would be helpful.Folger
See https://mcmap.net/q/392658/-is-there-a-way-to-create-an-nsdecimal-without-using-nsnumber-and-creating-autoreleased-objectsSubtotal
With this code, the compiler tells me it's an "incompatible type for argument 1 of 'decimalNumberWithDecimal:' Any thoughts as to why? Thanks again!Insect
If some one help you to solve your issue, remember to accept the answer.Fluvial
F
5

Try this:

NSDecimalNumber *budgetNumber = [NSDecimalNumber decimalNumberWithString:@"1.00"];

PS: Adding solution for the second issue stated in comments

(void)configureCell:(UITableViewCell *)cell withEnvelope:(NSManagedObject *)model{ 
     UILabel *envelopeNameLabel = (UILabel *) [cell viewWithTag:1];

     envelopeNameLabel.text = [model valueForKey:@"name"]; 

     UILabel *envelopeBudgetLabel = (UILabel *) [cell viewWithTag:2];
     envelopeBudgetLabel.text = [model valueForKey:@"budget"];
     }

'NSInvalidArgumentException', reason: '-[NSDecimalNumber isEqualToString:]: unrecognized selector sent to instance 0x653fc80' .

This issue is caused by assigning a decimal number to a string. You have to get the string representation before assigning it to the label. Something like this:

envelopeBudgetLabel.text = [[model valueForKey:@"budget"] description];
Fluvial answered 6/3, 2011 at 23:45 Comment(11)
Thanks @Manu. Tried it and it compiles fine, but the app crashes. The log shows: Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSDecimalNumber isEqualToString:]: unrecognized selector sent to instance 0x630db50'Insect
I hit enter before I was done typing...Any thoughts as to why it won't accept this code?Insect
I have tested the code and working fine. The error may be caused by other code? Comment out the last two lines of the given code and tell us the result.Fluvial
Hmmm...well, @Manu, I believe you may be on to something. Commented out, the log shows the same error. When I try to add a new object, it shows: *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSDecimalNumber isEqualToString:]: unrecognized selector sent to instance 0x653fc80' . Thanks.Insect
I guess you are trying to retrieve the decimal number from core data and comparing it with a string directly, aren't you? Post the code where you use the isEqualToString: comparison or decimal number comparison.Fluvial
No, this is in my creating a new entity method. All I'm trying to do, is setValue: of the decimal attribute of my entity. I don't have any comparison code to show. For some reason, when Core Data tries to create the new entity object, it doesn't like the way I'm trying to set the value of the decimal attribute. thanks again for taking the time to try and sort this out with me.Insect
I was talking about the the part where you retrieve information from core data( How you read the data in other part of your code). There is nothing wrong in using decimalNumberWithString: to create a decimal number.Fluvial
I'm using a uitableview with a custom uitableview cell. Here is my configure cell method: - (void)configureCell:(UITableViewCell *)cell withEnvelope:(NSManagedObject *)model{ UILabel *envelopeNameLabel = (UILabel *) [cell viewWithTag:1]; envelopeNameLabel.text = [model valueForKey:@"name"]; UILabel *envelopeBudgetLabel = (UILabel *) [cell viewWithTag:2]; envelopeBudgetLabel.text = [model valueForKey:@"budget"]; } If I create the app without the decimal attribute, it works great. As soon as I add back in the decimal attribute, it terminates when I try to add a new entity object. Thoughts?Insect
try this instead of last line and let me know the result envelopeBudgetLabel.text = [[model valueForKey:@"budget"] description];Fluvial
Well, it's on the right track now! What is the "description" argument? Thank you so much @Manu!Insect
I will edit the answer to explain this for future users. Remember to accept the answer. :)Fluvial
S
3

NSDecimalNumber is very precise and should be constructed precisely:

NSDecimalNumber *budgetNumber = [NSDecimalNumber decimalNumberWithMantissa:1 exponent:0 isNegative:NO];

Will give you a NSDecimalNumber representation of 1. If you wanted a NSDecimalNumber representation of -12.345 then it would be constructed:

NSDecimalNumber *budgetNumber = [NSDecimalNumber decimalNumberWithMantissa:12345 exponent:-3 isNegative:YES];
Sokoto answered 8/3, 2011 at 8:43 Comment(4)
thank you. I just picked up your book on Core Data the other day. Very helpful!Insect
thanks for your nice explanation. But I can't observe any precision loss even if I constructed it from string. (of course I cant check for 30 over decimal places). Is there a real difference?Fluvial
IMHO it is a difference in performance. Parsing strings is expensive.Sokoto
Also, note that NSDecimalNumber provides the class method one which generates the precise number 1.Tenebrific

© 2022 - 2024 — McMap. All rights reserved.