Custom NSFormatter to accept only numbers - objective-c

I have searched for an answer and tried a lot of user examples posted at SO, however they do not seem to answer my question.
In the UK the majority or area codes begin with zero, I have a single NSTextField and have created a customer NSNumberFormatter. I want my NSTextField to accept numbers beginning with zero, I dont want to use the NSNumberFormatter Padding option as the length of phone number may very but always start with zero.
- (BOOL)isPartialStringValid:(NSString*)partialString newEditingString:(NSString**)newString errorDescription:(NSString**)error {
if (partialString.length <= 0 || [partialString rangeOfCharacterFromSet:[[NSCharacterSet characterSetWithCharactersInString:#"0123456789."] invertedSet]].location != NSNotFound) {
NSLog(#"This is not a positive integer");
return NO;
}
return YES; } #end
The above example works and allows any number to be entered of any length but will always removes the leading zero upon moving focus away from the NSTextField.
Example numbers:
01202
01134
01103111345
How can I stop the leading zero being removed?
Thank you for reading.

Have you tried looking at a library to manage phone numbers such as
libPhoneNumber-iOS it's got most of this covered. Granted it maybe overkill if you're just looking at working with UK numbers.
I could copy the code here, but it probably more efficient to check out the framework. It's been around for years and years now so it well tested and I've used it many times when working for o2 in their apps. If you don't decide to use it, just look through the code, you'll find your answer there.
I see you're looking for mac you can do it but it's effort

Related

Objective C: calculator app - currentNumber = currentNumber * 10 + digit;

I am reading "Programming in Objective-C" 4th Ed. by Stephen G. Kochan. In the book, there is a sample code for creating a Calculator application for the iPhone. I understand the code, at least 90% of it. - There is a Fraction class that has methods to store fraction objects and that describe how to perform different basic fraction arithmetic operations
- In addition to that, there is a calculator class that runs the appropriate methods from the Fraction class depending on whether the user is trying to sum, divide etc.
The view controller has the following method for when the user presses a number in the interface:
-(IBAction)clickDigit:(UIButton *)sender {
int digit = sender.tag; //sender or the argument inthis case is the button
[self processDigit:digit];
}
As you see this method is now called:
-(void) processDigit:(int)digit {
currentNumber = currentNumber * 10 + digit;
[displayString appendString:
[NSString stringWithFormat:#"%i", digit]];
display.text = displayString;
}
My ONLY question (and probably the one with the most simple answer) is: Why is currentNumber always multiplied by 10? The value of currentNumber is always 0 by the time the compiler enters the method above (I verified this using the debugger in XCode) so i dont get why we even have to multiply it by 10. I did delete that multiplication and the results are incorrect, i just cannot figure out why yet.
Thank you
Maybe the best way to think about this is with an example.
Imagine the user has clicked the following digits in order: 1, 2. Then, assuming the code is working, the numeric value of currentNumber should be 12.
Now imagine the user next clicks on '3'. Now you want the value to be 123. You can get this by multiplying the previous value (12) by 10 and then adding the 3. If they then click on a '4', the value should become 1,234, which is achieved by 10 * 123 + 4. And so on.
Imagine your calculator has "123" on the screen and you want to turn this into "1234". If it was a string you can add "4" to the end, and it works fine. But it's an integer, and if you add 4 to the integer value you get 127. So what you do is take 123, multiply by 10 to give you 1230, then add the 4 to get 1234.
The debugger must be misleading you, as it sometimes does.
Consider that if taking the multiplication out makes the result wrong then the multiplication obviously does something!
Try the following for debugging only:
int lastCurrentNumber = currentNumber;
currentNumber = 10 * lastCurrentNumber + digit;
Now in the debugger check the values of lastCurrentNumber, currentNumber and digit as you step through these two statements.
The *10 is used to move digits through the various places in decimal numbers (tens place, hundreds place, etc.)
It's kind of a "hack" to avoid having to use an array. Other calculator apps "pop" and "push" digits onto an array, this allows for more powerful operations as well as manipulation of non-decimal numbers (binary, hex, etc.)
The free iOS development course on iTunes U includes a calculator app that uses an array. If you'd like to compare the difference, you can download the source code here:
http://www.stanford.edu/class/cs193p/cgi-bin/drupal/
It also has a Fraction object but doesn't use the *10 method.

UITextChecker 25 Letter Words

I believe this is an Apple bug, but wanted to run it by you all and see if anyone else had run into the same/similar issues.
Simply, Apple's UITextChecker finds all words 25 letters or more as valid, spelled correctly words. Go ahead and open up Notes on your iOS device (or TextEdit on OS X) and type in a random 24 letter word. Hit enter, underlined red, right? Now add one more letter to that line so it is a 25 letter word. Hit enter again, underline red, right ... nope!
I don't know if this is related, but I have a similar unanswered question out there (UITextChecker is what dictionary?) questioning what dictionary is used for UITextChecker. In /usr/share/dict/words the longest word is 24 letters. Seems rather coincidental that 25 letters would be the first length of word that is not in the dictionary and it is always accepted as a valid word. But I don't know if that word list is the dictionary for UITextChecker.
This is important to note for anyone that might be confirming the spelling of a given word for something like a game. You really don't want players to able to use a random 25 letters to spell a word and most likely score massive points.
Here's my code to check for valid words:
- (BOOL) isValidWord:(NSString*)word {
// word is all lowercase
UITextChecker *checker = [[UITextChecker alloc] init];
NSRange searchRange = NSMakeRange(0, [word length]);
NSRange misspelledRange = [checker rangeOfMisspelledWordInString:word range:searchRange startingAt:0 wrap:NO language:#"en" ];
[checker release];
BOOL validWord = (misspelledRange.location == NSNotFound);
BOOL passOneCharTest = ([word length] > 1 || [word isEqualToString:#"a"] || [word isEqualToString:#"i"]);
BOOL passLengthTest = ([word length] > 0 && [word length] < 25); // I don't know any words more than 24 letters long
return validWord && passOneCharTest && passLengthTest;
}
So my question to the community, is this a documented 'feature' that I just haven't been able to locate?
This is likely to be caused by the algorithm used for spell-checking itself although I admit it sounds like a bit of a hole.
Even spell-checkers that use a dictionary often tend to use an algorithm to get rid of false negatives. The classic is to ignore:
(a) single-character words followed by certain punctuation (like that (a) back there); and
(b) words consisting of all uppercase like NATO or CHOGM, assuming that they're quite valid acronyms.
If the algorithm for UITextChecker also considers 25+-letter words to be okay, that's just one of the things you need to watch out for.
It may well be related to the expected use case. It may be expected to be used as not so much for a perfect checker, but more as a best-guess solution.
If you really want a perfect filter, you're probably better off doing your own, using a copy of the dictionary from somewhere. That way, you can exclude things that aren't valid in your game (acronyms in Scrabble®, for example).
You can also ensure you're not subject to the vagaries of algorithms that assume longer words are valid as appears to be the case here. Instead you could just assume any word not in your dictionary is invalid (but, of course, give the user the chance to add it if your dictionary is wrong).
Other than that, and filing a query/bug with Apple, there's probably not much else you can do.

Convert from pounds to kilograms, possibly using Core Data

In my app, numbers are displayed as pounds. I need to add an option to use kilograms instead. Does anyone know how to go about this? I'm using Core Data to store numbers. I know I can do it all manually by using an if statement then doing a conversion, but there must be better way.
EDIT
Actually, I think I ran into a huge problem. It isn't as simple as converting numbers. Because I am using a picker and I want to offer international imperial support, The picker should display whole, sensible numbers in kg. If I just convert the numbers to kg, I will get decimal numbers which people will not know how to use. Any suggestions?
https://github.com/davedelong/DDUnitConverter
NSNumber *weightInPounds = [NSNumber numberWithInt:42];
NSNumber *weightInKilos = [[DDUnitConverter massUnitConverter] convertNumber:weightInPounds fromUnit:DDMassUnitUSPounds toUnit:DDMassUnitKilograms];
Pretty simple.
I would suggest using a custom NSFormatter to convert your numbers into strings for display. You would always store your data in one format, while providing the ability to display it in any format. You will need a simple setting (stored via NSUserDefaults) to tell the formatter what format to use. Some benefits of this are that you only have to deal with this while displaying the numbers. Since you already have to convert the numbers to strings to display them, there will be very few changes to your code. Also, you won't have to change your core data stores at all, since the setting is stored in the app's preferences. You can even subclass NSNumberFormatter for automatic formatting of the number after conversion. Here is an example implementation:
- (NSString *)stringForObjectValue:(NSNumber *)number {
double val = [number doubleValue];
BOOL isKGs = [[NSUserDefaults standardUserDefaults] boolForKey:#"wantsKGs"];
if(isKGs) val *= 0.45359237;
NSString *str = [super stringForObjectValue:[NSNumber numberWithDouble:val]];
if(isKGs) return [str stringByAppendingString:#" kg"];
return [str stringByAppendingString:#" lbs"];
}
For more information about custom formatters, see Creating a Custom Formatter.
there are so many ways you could do this.
I'd have to make some assumptions about your app, but if you want to have the option to change (globally) from lbs to kgs then i would probably have a settings dialog in your app so that a user can persist their decision to see things in lbs or kgs, i would then persist this in settings for your app and use this setting as part of your app's initialization. then, wherever you show a value of lbs or kgs you just need to check for the user defined setting and adjust the values accordingly (and probably any labels in the app as well) this would be as simple as having a check in the code that retrieves the values from core date
Check setting persist this as a globally accessible piece of state; this could be a member in your app delegate, a singleton that contains settings or simply requesting the setting wherever you need to check it. Then, in code that access the lbs data, check the setting, if its set to kg do the calculation and return that back from the data access code to the view.
It may be a good idea to code it to work always with the units and scaling as variables.
The units and scaling would be "lbs" and 1.0, or "kgs" and 0.45359237, or whatever.

Using ideas from Uncle Bob's Clean Code in real-world code

I just finished reading the "Functions" chapter from Uncle Bob's Clean Code. The main advice was to make sure that functions are short -- really short. And they should only do one thing per level of abstraction. Here's a function from an app I'm making to learn Cocoa (idea from Andy Matuschak).
- (IBAction)go:(id)sender
{
NSString *output = nil;
if ([[nameInputField stringValue] isEqualToString:#""])
{
output = #"Please enter your name";
}
else
{
NSString *date = [[NSDate date] descriptionWithCalendarFormat:#"%A, %B %d"
timeZone:nil
locale:[[NSUserDefaults standardUserDefaults] dictionaryRepresentation]];
output = [NSString stringWithFormat:#"Hello, %#! Today is %#.", [nameInputField stringValue], date];
}
[responseOutputField setStringValue:output];
}
Basically, this function reads a name from a text field (nameInputField) and outputs a message to another text field (responseOutputField) I'm wondering a) if this function does 'one thing' per level of abstraction and b) how to make it shorter.
I disagree that this function is at the right level. The core computation of working out what to output based on current input should be factored into another function. This will make that computation much more testable (since you don't need any text fields, you can unit test in isolation) and reusable, since it has much less contextual baggage. As it is, the function is hard-wired to a specific use and so is not reusable.
As it is, how do you test it without actually running the application?
It does two things. First it gets/determines the output to print. Then it prints it. You could separate these. But I wouldn't. That seems like going too far to me.
I think this function does a reasonable amount of work, and does not need to be broken down further.
I would suggest changing the name of the function to more clearly describe what it does (i.e. updateResponse). This will make the code easier to understand, when looking at the source and when looking at the NIB in interface builder. Also, if you can't find a name that succinctly describes what the function does, its a tip that you are violating the "one thing" goal.
You also ask how to make this code shorter. I think in this case you might be able to use bindings to keep the responseOutputField in sync with the nameInputField, without any code at all (depending on how exactly you want things to behave).

How to find out if there is an "." in an NSString?

Have got an
NSString *str = #"12345.6789"
and want to find out if there is that "." character inside of it. I'm afraid that there are ugly char-encoding issues when I would just try to match an #"." against this? How would you do it to make sure it always finds a match if there is one?
I just need to know that there is a dot in there. Everything else doesn't matter.
You can use rangeOfString: message to get the range where your "." is.
The prototype is:
- (NSRange)rangeOfString:(NSString *)aString
You can find more info about this message in: Mac Dev Center
There would be something like this:
NSRange range;
range = [yourstring rangeOfString:#"."];
NSLog(#"Position:%d", range.location);
If you need to, there is another message ( rangeOfString:options: ) where you can add some options like "Case sensitive" and so on.
If [str rangeOfString:#"."] returns anything else than {NSNotFound, 0}, the search string was found in the receiver. There are no encoding issues as NSString takes care of encoding. However, there might be issues if your str is user-provided and could contain a different decimal separator (e.g., a comma). But then, if str really comes from the user, many other things could go wrong with that comparison anyway.
To check . symbol, it will be useful.
if ([[str componentsSeparatedByString:#"."] count]>1) {
NSLog(#"dot is there");
}else{
NSLog(#"dot is not there");
}
If what you really want to do is determine whether the string represents a number with a fractional part, a better solution is to feed the string to a number formatter, then examine the number's doubleValue to see whether it has a fractional part.
For the latter step, one way would be to use the modf function, which returns both the fractional part (directly) and the integral part (by reference). If the fractional part is greater than zero (or some appropriately small fraction below which you're willing to tolerate), then the number has a fractional part.
The reason why this is better is because not everybody writes decimal fractions in the “12345.6789” format. Some countries use a comma instead, and I'm sure that's not the only variation. Let the number formatter handle such cases for you.
I wrote a little method to make things a little more natural if you use this sort of thing a whole bunch in your project:
+(BOOL)seeIfString:(NSString*)thisString ContainsThis:(NSString*)containsThis
{
NSRange textRange = [[thisString lowercaseString] rangeOfString:[containsThis lowercaseString]];
if(textRange.location != NSNotFound)
return YES;
return NO;
}
Enjoy!