-3

I am a beginner Objective-C programmer and I was building a calculator as my first app. I am using an NSNumberFormatter to format the Calculator’s display. It converts NSNumber to NSString correctly, but doesn’t parse NSString to NSNumber right if they have a comma separator. Here’s the code:

- (IBAction)digitPressed:(NSButton *)sender {
    if (userIsEnteringANumber) {
        NSNumber *number = [formatter numberFromString:[self.calDisplay.stringValue stringByAppendingString:sender.title]];
        self.calDisplay.stringValue = [formatter stringFromNumber:number];
    }
    else {
        self.calDisplay.stringValue = sender.title;
        userIsEnteringANumber = YES;
    }
}

If calDisplay.stringValue = @“2,569”, then pressing another digit sets number to nil.

duci9y
  • 4,128
  • 3
  • 26
  • 42

3 Answers3

2

Pragmatically I would simply remove the comma before parsing the string into a number then it must work.

 NSString *s = [self.calDisplay.stringValue 
                stringByReplacingOccurrencesOfString:@"," withString:@""];

Leaving you with

- (IBAction)digitPressed:(NSButton *)sender {
   if (userIsEnteringANumber) {
       NSString *s = [self.calDisplay.stringValue stringByReplacingOccurrencesOfString:@"," withString:@""];
       NSNumber *number = [formatter numberFromString:[s stringByAppendingString:sender.title]];
       self.calDisplay.stringValue = [formatter stringFromNumber:number];
   } else {
       self.calDisplay.stringValue = sender.title;
       userIsEnteringANumber = YES;
   }
}
hol
  • 8,255
  • 5
  • 33
  • 59
  • GENIUS!!! Thanks a lot! It was soooo simple! But there’s a problem. The calculator doesn’t work with more than 3 decimal places. After I input a number with 3 decimal places, pressing another digit button just does random things with the decimal part. What’s wrong? – duci9y Aug 25 '12 at 11:19
  • I just found out that’s because of `NSNumberFormatterDecimalStyle`. I fixed it by creating a custom formatter. – duci9y Aug 25 '12 at 11:27
1

I believe this is what happens:

The string you have is "2,569". Which is two thousand something. This works fine, because the thousands delimiter is a comma.

After another button press (e.g. 1), your string becomes "2,5691". This is not a proper number, because it has the thousands delimiter (comma) wrong, hence the nil number. "25,691" would have been correct, but you have "2,5691".

Try this:

- (IBAction)digitPressed:(NSButton *)sender {
    if (userIsEnteringANumber) {
        double previous = [[self.calDisplay.stringValue] doubleValue];
        double pressed = [sender.title doubleValue];
        NSNumber *number = [NSNumber numberWithDouble:previous*10+pressed];
        self.calDisplay.stringValue = [formatter stringFromNumber:number];
    }
    else {
        self.calDisplay.stringValue = sender.title;
        userIsEnteringANumber = YES;
    }
}
bogdansrc
  • 1,338
  • 2
  • 15
  • 28
  • Please check if your code works before posting it. NSInteger is not an object. You can set a pointer to an NSInteger. The reason for the problem *may* be correct but your code does the same thing as mine. EDIT: I just found out that the reason for the problem is correct. Thanks for that. But there’s another problem with your code. It doesn’t work with decimal points. – duci9y Aug 19 '12 at 17:10
  • 2
    Sorry, I assumed you're able to change it and didn't check for typos. Modified it to include doubles, it should work with decimal points, but I won't test it, that's your job. – bogdansrc Aug 19 '12 at 20:16
  • Unfortunately, the updated code doesn’t work. It still won’t work with decimal points. For example, if the number on the screen is 260 pressing “.” followed by 2 would produce 2,602 instead of 260.2. – duci9y Aug 20 '12 at 06:21
0

to expand on the bogdansrc's answer pointing out that the formatter is not at fault here, one way to solve this (homework?) problem that allows entering digits for strings that already appear as double in your display would be as follows:

- (IBAction)digitPressed:(NSButton *)sender {
    if (userIsEnteringANumber)
    {
        double previous = self.calDisplay.stringValue.doubleValue;
        NSString* pressed = sender.title;
        NSString* newNumber = [NSString stringWithFormat:@"%g%s", previous, pressed];
        self.calDisplay.stringValue = [formatter stringFromNumber:[newNumber doubleValue]];
    }
    else
    {
        self.calDisplay.stringValue = sender.title;
        userIsEnteringANumber = YES;
    }
}

of course, this is not really ideal MVC, as the code relies on the View to track its Model … and by so doing, it's hard to be able to know from only the code snippet you provided how to transition from 260 to 260.4 when 4 is pressed after getting into the state that is supposed to be a fractional decimal number.  is the decimal place being shown and tracked as the last character in stringValue?  if so, the above will break because the "." at the end will get lost.  if not, well then the Model is basically spread out partly in the View and partly in separate state, which is even less ideal.

Community
  • 1
  • 1
john.k.doe
  • 7,533
  • 2
  • 37
  • 64
  • A friend with ASP.NET background mentioned that this was not good MVC, but he said I can begin like this and move on to more complex MVC structures in the future. This is not homework, it’s just a side project I took up to learn Objective C. The decimal point button just appends a “.” at the end of calDisplay.stringValue after checking for some conditions. And yes, the code was broken because of that. Perhaps you could update your answer and help me out? – duci9y Aug 21 '12 at 08:42
  • you could accomplish this by seeing if "." is in the range of the returned by `[self.calDisplay.stringValue rangeOfString:"."]`. as you mentioned that this is a side project in order to learn objective C, i will leave it as a bit of research for you to look up in the apple docs what the result type of `rangeOfString:` is, how you can use those to decide whether double previous can just be calculated as seen above or if you'll have to do it differently, and how this will lead you to the ultimate number to pass to the formatter to end up in `self.calDisplay.stringValue`. – john.k.doe Aug 21 '12 at 09:37