bug of calculating float values objective-c - objective-c

does anyone knows about a bug of calculating float values (in my case currency values converted from text to float). I've been testing it on the simulator and all calculated values are correct. Then testing on the iphone device itself, every value displayed with 0.59 more. On the iPad device I've got just 0.15 more on every value.
Here's my Code
- (void)viewDidLoad
{
[super viewDidLoad];
// current account balance from Coredata Dataset
if (!self.FSDataSet.konto || [self.FSDataSet.konto isEqualToString:#""]) {
self.txtKontostand.text = #"Nicht möglich!";
} else {
// fetch request for current changes of currency values
NSFetchRequest *fetchRequestFahrschueler = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([FSKontoUnterTab class])];
NSPredicate *predicateKundenNr = [NSPredicate predicateWithFormat:#"kundennr == %#", self.FSDataSet.kundennr];
fetchRequestFahrschueler.predicate = predicateKundenNr;
// put datasets in array
NSArray *ergebnisFahrschueler= [[[CoreDataHelper sharedInstance] managedObjectContext] executeFetchRequest:fetchRequestFahrschueler error:nil];
// variables to calculate the new account balance
CGFloat soll;
CGFloat haben;
CGFloat konto;
// account balance string converting to a flot value
// comma replace with point
NSString *kontostand = [self.FSDataSet.konto stringByReplacingOccurrencesOfString:#"," withString:#"."];
CGFloat testKonto = kontostand.floatValue;
// NSArray Iterator workaround
// loop array and assign current dataset from entity (the managed object class)
for (NSInteger i = 0; i < [ergebnisFahrschueler count]; i++) {
FSKontoUnterTab *myset = [ergebnisFahrschueler objectAtIndex:i];
CGFloat gesamtpreis = [myset.preis stringByReplacingOccurrencesOfString:#"," withString:#"."].floatValue;
// positive currency values
CGFloat aktHaben = [myset.bar stringByReplacingOccurrencesOfString:#"," withString:#"."].floatValue;
// calculate
soll = soll + gesamtpreis;
haben = haben +aktHaben;
}
//konto = soll-haben;
konto = (testKonto - soll)+haben;
// convert back to string and display in textfield
self.txtKontostand.text = [[NSString stringWithFormat:#"%.2f", konto] stringByReplacingOccurrencesOfString:#"." withString:#","];
}

Related

XLForm - How to hide a row depending on the value of another row?

I could need some help.
I'm using XLForm in my Objective-C project. I have a first row with a picker where you have four different options. Then there is a second picker. But the second picker should only be available if a certain value is selected in the first picker.
I know there is a description on the github-site but I don't really understand what to do. So please help me doing this.
Here are the relevant parts of my code:
row = [XLFormRowDescriptor formRowDescriptorWithTag:#"repeat" rowType:XLFormRowDescriptorTypeSelectorPickerViewInline title:#"Wiederholen:" ];
row.cellClass = [LehrerXLFormInlineSelectorCell class];
NSMutableArray *selectionArray = [NSMutableArray array];
for (NSNumber *item in [APIDataReplacement appointmentRepeatingList]) {
NSString *title = [APIDataReplacement appointmentRepeatingToString:item.intValue];
[selectionArray addObject:[XLFormOptionsObject formOptionsObjectWithValue:item displayText:title]];
}
row.selectorOptions = selectionArray;
if ([selectionArray count] == 0) {
[row setDisabled:#YES];
}
if (aItem) {
int repeatingID = [[aItem appointmentRepeatingId] intValue];
NSString *title = [APIDataReplacement appointmentRepeatingToString:repeatingID];
row.value = [XLFormOptionsObject formOptionsObjectWithValue:[NSNumber numberWithInt:repeatingID] displayText:title];
}else{
NSNumber *first = [[APIDataReplacement appointmentRepeatingList] firstObject];
NSString *title = [APIDataReplacement appointmentRepeatingToString:first.intValue];
row.value = [XLFormOptionsObject formOptionsObjectWithValue:first displayText:title];
}
[section addFormRow:row];
section = [XLFormSectionDescriptor formSectionWithTitle:#""];
[form addFormSection:section];
row = [XLFormRowDescriptor formRowDescriptorWithTag:#"weekday" rowType:XLFormRowDescriptorTypeSelectorPickerViewInline title: #"Wochentag:"];
row.cellClass = [LehrerXLFormInlineSelectorCell class];
NSMutableArray *selectionArray1 = [NSMutableArray array];
for (NSNumber *item in [APIDataReplacement dayList]) {
NSString *title = [APIDataReplacement dayToString:item.intValue];
[selectionArray1 addObject:[XLFormOptionsObject formOptionsObjectWithValue:item displayText:title]];
}
row.selectorOptions = selectionArray1;
if (aItem) {
// AppointmentRepeating *currentRepeat = [aItem appointmentRepeating];
int dayID = [[aItem startday] intValue];
NSString *title = [APIDataReplacement dayToString:dayID];
row.value = [XLFormOptionsObject formOptionsObjectWithValue:[NSNumber numberWithInt:dayID] displayText:title];
}else{
NSNumber *first = [[APIDataReplacement dayList] firstObject];
NSString *title = [APIDataReplacement dayToString:first.intValue];
row.value = [XLFormOptionsObject formOptionsObjectWithValue:first displayText:title];
}
[section addFormRow:row];
section = [XLFormSectionDescriptor formSectionWithTitle:#""];
[form addFormSection:section];
These are the two pickers. I think I should do something in the formRowDescriptorValueHasChanged-method, but I don't know what. If the first picker has the value "20" then the second picker should be hidden.
Really appreciate your help.
For your second XLFormRowDescriptor you should:
secondRow.hidden = [NSString stringWithFormat:#"$%# == 20", firstRow];
firstRow is the first XLFormRowDescriptor.
This actually creates an NSPredicate that is automatically evaluated whenever values change and sets the visibility appropriately.
Taken from XLForm's example:
For example, you could set the following string to a row (second) to
make it disappear when a previous row (first) contains the value
"hide".
second.hidden = [NSString stringWithFormat:#"$%d contains[c] 'hide'", [first.value intValue]];
Edit: I changed the predicate to work with NSNumber values.

UserDefaults - NSMutibleArray Loop

The Mutible array contains doubles
It takes the currently saved array adds new doubles then re-saves it.
NSUserDefaults *defaultDefects = [NSUserDefaults standardUserDefaults];
NSMutableArray *loadDefects = [defaultDefects objectForKey:#"defaultDefects"];
[loadDefects addObject:[NSNumber numberWithDouble:self.defectPositionX ]];
[loadDefects addObject:[NSNumber numberWithDouble:self.defectPositionY ]];
[defaultDefects setObject:loadDefects forKey:#"defaultDefects"];
Then to load them I require this
NSUserDefaults *defaultDefects = [NSUserDefaults standardUserDefaults];
NSMutableArray *loadDefects = [defaultDefects objectForKey:#"defaultDefects"];
//in here I need a foreach loop so it would be something like
double defectX = 0;
double defectY = 0;
int keyValue;
foreach (loadDefects as key => value) {
double defectX = [[loadDefects objectAtIndex:keyValue] doubleValue];
keyValue++;
double defectY = [[loadDefects objectAtIndex:keyValue] doubleValue];
keyValue++;
CGContextMoveToPoint(context, defectX, defectY);
}
I've wrote this to make sense programatically, not the correct way of writing it in Objective-C as that is what I'm trying to figure out.. Hopefully you can see what I'm trying to achieve.
As I understood you need make for cycle with step "2" for retrieving X and Y in one cycle step. Try this:
for (int i = 0; i < loadDefects.count; i += 2) {
double defectX = [loadDefects[i] doubleValue];
double defectY = [loadDefects[i+1] doubleValue];
CGContextMoveToPoint(context, defectX, defectY);
}
Also don't forget initialize loadDefects array at first app launch and save changes in NSUserDefaults:
NSMutableArray *loadDefects = [defaultDefects objectForKey:#"defaultDefects"];
if (loadDefects == nil) {
loadDefects = [NSMutableArray array];
}
// ...
// Add elements to array and store it defaultDefects here
// ...
[defaultDefects synchronize];

How to restrict number of fraction digits when parsing number from string?

I want to restrict the number of fraction digits a user is allowed to enter into a UITextField that only accepts (localized) numeric input.
Example with 4 fraction digits allowed:
Good: 42, 10.123, 12345.2345
Bad: 0.123456, 6.54321
Right now, I'm using NSNumberFormatter's numberFromString: in the UITextField delegate's textField:shouldChangeCharactersInRange:replacementString: to determine whether it's a legal numeric value.
Unfortunately, NSNumberFormatter seems to ignore maximumFractionDigits in numberFromString:. In tests using getObjectValue:forString:range:error: I had the same problem, and range also was the full length of the string afterwards (unless I start entering letters; then range indicates only the part of the string with digits):
NSNumberFormatter* formatter = [[NSNumberFormatter alloc] init];
formatter.maximumFractionDigits = 3;
formatter.roundingMode = NSNumberFormatterRoundHalfUp;
formatter.generatesDecimalNumbers = YES;
NSDecimalNumber* n = (NSDecimalNumber*)[formatter numberFromString:#"10.12345"];
NSLog(#"Number: %#", n.description); // expected: 10.123, but is: 10.12345
How to best restrict the number of fraction digits in user input?
after you get the unrestricted number, you can use stringWithFormat on that number to create a string with a certain number of decimal places.
eg.
double number = myTextField.text.doubleValue;
NSString *restrictedString = [NSString stringWithFormat:#"%.4f", number];
There are a few ways to do this, but the easiest is probably to split the string into two parts (you will have to localize the '.') and check the length of the second part, like this:
- (BOOL)LNNumberIsValid:(NSString *)string
{
NSArray *numArray = [string componentsSeparatedByString:#"."];
if ([numArray count] == 2)
if ([[numArray objectAtIndex:1] length] > 4)
return NO;
return YES;
}
// Tests
NSLog(#"42: %i", [self LNNumberIsValid:#"42"]); // 1
NSLog(#"10.123: %i", [self LNNumberIsValid:#"10.123"]); // 1
NSLog(#"12345.2345: %i", [self LNNumberIsValid:#"12345.2345"]); // 1
NSLog(#"0.123456: %i", [self LNNumberIsValid:#"0.123456"]); // 0
NSLog(#"6.54321: %i", [self LNNumberIsValid:#"6.54321"]); // 0
EDIT:
The problem with the code that you added to your question is that you are printing the description of the NSDecimalNumber, which is not localized or limited to the number of digits. The NSDecimalNumber itself stores everything that you give it, so you need to change the original string (like my example above) if you want to change that. However, once you have your NSDecimalNumber, you can use the same number formatter to convert it back to a string in the format that you like:
NSNumberFormatter* formatter = [[NSNumberFormatter alloc] init];
formatter.maximumFractionDigits = 3;
formatter.roundingMode = NSNumberFormatterRoundHalfUp;
formatter.generatesDecimalNumbers = YES;
NSDecimalNumber* n = (NSDecimalNumber*)[formatter numberFromString:#"10.12345"];
NSString *s = [formatter stringFromNumber:n];
NSLog(#"Number: %#", s); // expected: 10.123, and is: 10.123
The way I solved this is by checking the position of the decimal separator and making sure that the insertion either is before that position or the insertion would not exceed the maximum number of fraction digits.
Also, I check that the input of a new separator does not occur at a place that would lead to more then the allowed fraction digits and that not more than one separators can be inserted
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSString *separator = self.numberFormatter.decimalSeparator;
if(string.length == 0) {
// Empty String means deletion, always possible
return YES;
}
// Check for valid characters (0123456789 + decimal Separator)
for (int i = 0; i < [string length]; ++i) {
unichar c = [string characterAtIndex:i];
if (![self.legalCharSet characterIsMember:c])
{
return NO;
}
}
// Checks if input is separator
if([string isEqualToString:separator]) {
// Check that separator insertion would not lead to more than 2 fraction digits and that not more than one separators are inserted
// (the MIN() makes sure that length - kMaxFractionDigits won’t be below 0 as length and location are NSUIntegers)
return range.location >= self.valueField.text.length - MIN(self.valueField.text.length,kMaxFractionDigits) && [self.valueField.text containsString:separator] == NO;
} else {
// Check if a separator is already included in the string
NSRange separatorPos = [self.valueField.text rangeOfString: separator];
if(separatorPos.location != NSNotFound) {
// Make sure that either the input is before the decimal separator or that the fraction digits would not exceed the maximum fraction digits.
NSInteger fractionDigits = self.valueField.text.length - (separatorPos.location + 1);
return fractionDigits + string.length <= kMaxFractionDigits || range.location <= separatorPos.location;
}
}
return YES;
}
The method may not be bullet proof but it should be sufficient for common text insertions.

Convert NSString to unsigned in Objective C

I want to convert an NSString to an unsigned int.
Why? Because I want to do parallel payment in PayPal.
Below I have given my coding in which I want to convert the NSString to an unsigned int.
My query is:
//optional, set shippingEnabled to TRUE if you want to display shipping
//options to the user, default: TRUE
[PayPal getPayPalInst].shippingEnabled = TRUE;
//optional, set dynamicAmountUpdateEnabled to TRUE if you want to compute
//shipping and tax based on the user's address choice, default: FALSE
[PayPal getPayPalInst].dynamicAmountUpdateEnabled = TRUE;
//optional, choose who pays the fee, default: FEEPAYER_EACHRECEIVER
[PayPal getPayPalInst].feePayer = FEEPAYER_EACHRECEIVER;
//for a payment with multiple recipients, use a PayPalAdvancedPayment object
PayPalAdvancedPayment *payment = [[PayPalAdvancedPayment alloc] init];
payment.paymentCurrency = #"USD";
// A payment note applied to all recipients.
payment.memo = #"A Note applied to all recipients";
//receiverPaymentDetails is a list of PPReceiverPaymentDetails objects
payment.receiverPaymentDetails = [NSMutableArray array];
NSArray *emailArray = [NSArray arrayWithObjects:#"abc#def.com",#"def#abc.com", nil];
for (int i = 1; i <= 2; i++) {
PayPalReceiverPaymentDetails *details = [[PayPalReceiverPaymentDetails alloc] init];
// Customize the payment notes for one of the three recipient.
if (i == 2) {
details.description = [NSString stringWithFormat:#"Component %d", i];
}
details.recipient = [NSString stringWithFormat:#"%#",[emailArray objectAtIndex:i-1]];
unsigned order;
if (i==1) {
order = [[feeArray objectAtIndex:0] unsignedIntValue];
}
if (i==2) {
order = [[amountArray objectAtIndex:0] unsignedIntValue];
}
//subtotal of all items for this recipient, without tax and shipping
details.subTotal = [NSDecimalNumber decimalNumberWithMantissa:order exponent:-4 isNegative:FALSE];
//invoiceData is a PayPalInvoiceData object which contains tax, shipping, and a list of PayPalInvoiceItem objects
details.invoiceData = [[PayPalInvoiceData alloc] init];
//invoiceItems is a list of PayPalInvoiceItem objects
//NOTE: sum of totalPrice for all items must equal details.subTotal
//NOTE: example only shows a single item, but you can have more than one
details.invoiceData.invoiceItems = [NSMutableArray array];
PayPalInvoiceItem *item = [[PayPalInvoiceItem alloc] init];
item.totalPrice = details.subTotal;
[details.invoiceData.invoiceItems addObject:item];
[payment.receiverPaymentDetails addObject:details];
}
[[PayPal getPayPalInst] advancedCheckoutWithPayment:payment];
Can anybody tell me how to do this conversion?
In my case I had to implement something like this (adapt to your needs):
NSString *myStringObject = [NSString stringWithFormat:#"%u", someObject.hash];
NSUInteger hashValue = (NSUInteger)myStringObject.longLongValue;
I originally used myStringObject.intValue, as suggested below, but then my integers were getting "clipped" because they were too big when assumed signed (but not too big unsigned due to the extra bit). Using myStringObject.longLongValue fixed the problem for me.
I should note that my strings were originally created using NSUIntegers (unsigned ints) so I didn't have to worry about parsing an integer that was too big.
Assuming your array has a string in it:
unsigned int order = (unsigned int)[[feeArray objectAtIndex:0] intValue];
There really is no NSString method to convert directly to unsigned int values. However if you can guarantee that none of your values are signed ints, then the above should work for you.
There is no conversion to unsigned integer, however there is a conversion to signed integer (NSInteger):
NSInteger order = [[freeArray objectAtIndex:0] integerValue];
NSLog(#"order=%ld", order);
or int:
int order = [[freeArray objectAtIndex:0] intValue];
NSLog(#"order=%d", order);

UIPicker with multiple components crashing

I am trying to create an app using UIPickerView with three components. The first component has 3 rows. The second component has 6 rows and the third component has 12 rows. Every time I scroll beyond row 3 in components 2 or 3 the application crashes and points to the first components array. I'm sure this is easy to fix but I'm lost. Thanks in advance.
-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row
inComponent:(NSInteger)component
{
{
NSString *resultString0 = [[NSString alloc] initWithFormat:
#"Sensor: %#",
[modelArray objectAtIndex:row]];
modelLabel.text = resultString0;
[resultString0 release];
}
{
NSString *resultString1 = [[NSString alloc] initWithFormat:
#"Pixels: %#",
[memoryArray objectAtIndex:row]];
memoryLabel.text = resultString1;
[resultString1 release];
NSString *firstString = horizFaceRecLabel.text;
float horizontalFace = [[horizontalArray objectAtIndex:row] floatValue];
float requiredFace = 100;
output1 = [firstString floatValue];
output1 = horizontalFace / requiredFace;
horizFaceRecLabel.text = [NSString stringWithFormat:(#"%.1f ft"), output1];
NSString *secondString = horizLicensePlateLabel.text;
float horizontalLicense = [[horizontalArray objectAtIndex:row] floatValue];
float requiredLicense = 45;
output2 = [secondString floatValue];
output2 = horizontalLicense / requiredLicense;
horizLicensePlateLabel.text = [NSString stringWithFormat:(#"%.1f ft"), output2];
NSString *thirdString = horizVisualIdLabel.text;
float horizontalVisual = [[horizontalArray objectAtIndex:row] floatValue];
float requiredVisual = 30;
output3 = [thirdString floatValue];
output3 = horizontalVisual / requiredVisual;
horizVisualIdLabel.text = [NSString stringWithFormat:(#"%.1f ft"), output3];
}
{
NSString *resultString2 = [[NSString alloc] initWithFormat:
#"Lens: %#",
[lensArray objectAtIndex:row]];
lensLabel.text = resultString2;
[resultString2 release];
{
NSString *firstDistString = faceRecLabel.text;
float angle = [[anglesArrayA objectAtIndex:row] floatValue];
float densityOne;
float densityTwo;
densityOne = [firstDistString floatValue];
densityTwo = (output1/2)/(sin(angle/2));
faceRecLabel.text = [NSString stringWithFormat:(#"%.1f ft"), densityTwo];
}
}
}
It looks like you're missing some if statements to control when each block of code gets called.
You have three separate blocks of code presumably for each component but since there's no condition to control the flow, all the blocks get executed whenever a row in any component is selected. (The third block also has another block inside it--don't know why you've written it like that.)
When you go beyond row 3 in the 2nd and 3rd components, the code for the 1st component runs and crashes when it tries to get the 4th row in the array for component 1 (which doesn't exist).
Since the component indexes are zero-based, the conditions should be something like:
if (component == 0)
{
//code for 1st component here...
}
else if (component == 1)
{
//code for 2nd component here...
}
else if (component == 2)
{
//code for 3rd component here...
}
You could also use a switch statement instead.