How to check if UITextFields are empty? - objective-c

I have a bunch of UITextFields where a user must enter a number (the keyboard is the number pad) before pressing a submit button. When the submit button is pressed, a "check" method is called that wants to check if the data is valid... aka not empty. Now this would be easy if it was just one textField but I have 14. I want a simple if-statement that checks if one of the fields or all of the fields are empty....
I have the follow UITextFields declared: number1, number2, number3 etc etc
and I have the follow strings declared which can take the value of the UITextField.text... they are declared: temp1, temp2, temp3 etc...
how would I go about making a pseudocode if statement like the one below?
Thanks
if (!valid)
{
NSLog (#"not valid)
}
else
{
//proceed to next method
}

I am supposing UITextField variable as *tfield so here is the solution
if (tfield.text.length > 0 || tfield.text != nil || ![tfield.text isEqual:#""])
{
//do your work
}
else
{
//through error
}

or you could just call
[myTextField hasText];
which will return NO if the field is empty.

I think something like this is what you want. It's just using isEqualToString: to check if the string is empty.
NSString *temp1 = number1.text;
NSString *temp2 = number2.text;
... ///< temp3, etc
if ([temp1 isEqualToString:#""]) {
// temp1 not valid
} else if ([temp2 isEqualToString:#""]) {
// temp2 not valid
} ... {
// temp3, etc
} else {
// Valid
}
You may want to trim whitespace characters when grabbing temp1 so that #" " would also be blank. For that, take a look at NSString's stringByTrimmingCharactersInSet: method like so:
NSString *temp1 = [number1.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
Update:
If you want to do it with an array you could do something like:
NSMutableArray *array = [NSMutableArray arrayWithCapacity:0];
[array addObject:number1.text];
[array addObject:number2.text];
... ///< number3, etc
BOOL ok = YES;
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([obj isEqualToString:#""]) {
ok = NO;
*stop = YES;
}
}];
if (ok) {
// Valid
} else {
// Not valid
}

Something like this would iterate through your UITextFields:
[self.view.subviews enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([obj isKindOfClass:[UITextField class]]) {
// do your checks
}
}];

you can put like this
if(![temp1 isEqualToString:#""] && ![temp2 isEqualToString:#""] ... ![temp14 isEqualToString:#""])
{
NSLog (#" valid);
}
else
{NSLog (#"not valid);
}

In Swift,
You can use this block of code.
if textField.text?.isEmpty {
//Return true if the textfield is empty or false if it's not empty.
}

Related

NSDictionary get value as string does not complain but lenngth or isEqualToString crashes

I got a Json like below as a response message.
data:{
type = DATA;
version = "4.51";
}
Which i process in below method, from the debugger it looks like that version no is string.
-(void)processResponse:(NSDictionary *)responseDictionary{
NSString *version = [responseDictionary valueForKey:#"version"];
if([version isEqualToString:#"4.51"]){ //line 3
NSLog(#"do something"); //crashes
}
}
But line 3 crashes.
My question is why this line crashes? And what is the best way to handle this type of dictionary message?
If this is data that originates outside your program, you must always check the types.
-(void)processResponse:(NSDictionary *)responseDictionary {
id value = responseDictionary[#"version"];
if ([value isKindOfClass: [NSString class]]) {
NSString *version = value;
if ([version isEqualToString: #"4.51"]) {
NSLog(#"do something"); //crashes
}
}
}
If this is all you're going to do, then you can shorten it a little bit with && short-circuiting, if you're careful.
-(void)processResponse:(NSDictionary *)responseDictionary {
NSString *version = responseDictionary[#"version"];
if ([version isKindOfClass: [NSString class]]
&& [version isEqualToString: #"4.51"]) {
NSLog(#"do something"); //crashes
}
}
Just be very careful with this, because it means that version exists beyond this if block and may not be the correct type.
Again, if this is precisely your problem, you can also simplify it by using isEqual:, which applies to all NSObject:
-(void)processResponse:(NSDictionary *)responseDictionary {
id version = responseDictionary[#"version"];
if ([version isEqual: #"4.51"]) {
NSLog(#"do something"); //crashes
}
}

Loop through text fields array and check if ALL are empty

Im looping through an array of UITextFields and checking if any of them are empty
NSArray*textFields = ...;
textFieldHasData = YES;
[textFields enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([obj isEqualToString:#""]) {
textFieldHasData = NO;
*stop = YES;
}
}];
if (!textFieldHasData) {
//Empty text fields found
}
I also want to check if ALL the textfields are empty in the array, rather than individually.
Reverse the logic:
NSArray *textFields = ...;
textFieldHasData = NO;
[textFields enumerateObjectsUsingBlock:^(UITextField *field, NSUInteger idx, BOOL *stop) {
if ([[field text] length] > 0) {
textFieldHasData = YES;
*stop = YES;
}
}];
if (!textFieldHasData) {
// All text fields are empty
}

Why would subclassing NSFormatter prevent me from editing NSTextField's input?

I'm trying to format two NSTextFields for SMPTE time codes, which have the format:
HH:MM:SS:FF. However, when the user switches the SMPTE code to drop-frame, the delimiter between SS and FF needs to switch to a ; (HH:MM:SS;FF). To do this, I've subclassed NSFormatter, and have it mostly working except for one very stubborn problem.
The text field accepts input just fine, but if I highlight-replace, backspace, delete, or insert any new characters into the text field, I get an NSBeep and I can't switch focus away from the text field. I can input new text if I delete the whole text field first, but not if I try to edit the existing input. Here are my implemented methods/overrides:
- (NSString*)stringForObjectValue:(id)obj
{
if ( ! [obj isKindOfClass:[NSNumber class]])
{
return nil;
}
NSMutableString *string = [NSMutableString stringWithString:#"00:00:00:00"];
int length = (int)[[obj stringValue] length];
int insertLocation = 9;
if (length == 1)
{
[string replaceCharactersInRange:NSMakeRange(10, 1) withString:[obj stringValue]];
}
else
{
while (length > 1)
{
NSString *temp = [[obj stringValue] substringFromIndex:length-2];
[string replaceCharactersInRange:NSMakeRange(insertLocation, 2) withString:temp];
obj = [NSNumber numberWithInt:[obj intValue]/100];
length -= 2;
insertLocation -= 3;
}
if (length == 1)
{
[string replaceCharactersInRange:NSMakeRange(insertLocation+1, 1) withString:[obj stringValue]];
}
}
return string;
}
- (BOOL)getObjectValue:(out __autoreleasing id *)obj forString:(NSString *)string errorDescription:(out NSString *__autoreleasing *)error
{
int valueResult;
NSScanner *scanner;
BOOL returnValue = NO;
scanner = [NSScanner scannerWithString: string];
[scanner scanString:#":" intoString:NULL];
[scanner scanString:#";" intoString:NULL];
if ([scanner scanInt:&valueResult] && ([scanner isAtEnd])) {
returnValue = YES;
if (obj)
{
*obj = [NSNumber numberWithInt:valueResult];
}
}
return returnValue;
}
At least at this point, I don't need to validate the input during editing, only when editing is finished. I tried implementing isPartialStringValid and just returning YES, but that didn't seem to help either. Any help would be greatly appreciated!
Ok, I just solved it by doing some more testing. It appears as though why it was failing is because getObjectValue was receiving the string with the delimiters in them and was not correctly removing them. I simply replaced the method with this:
- (BOOL)getObjectValue:(out __autoreleasing id *)obj forString:(NSString *)string errorDescription:(out NSString *__autoreleasing *)error
{
NSString *newString = [string stringByReplacingOccurrencesOfString:#":" withString:#""];
if (obj)
{
*obj = [NSNumber numberWithInt:[newString intValue]];
return YES;
}
return NO;
}
Now it works perfectly.

How can I remove all NSTableColumns from an NSTableView?

I am trying to implement a method to clear the NSTableView of all items AND columns. But I get a crash when I try to implement the following:
- (void)clearResultData
{
[resultArray removeAllObjects];
NSArray *tableCols = [resultTableView tableColumns];
if ([tableCols count] > 0)
{
id object;
NSEnumerator *e = [tableCols objectEnumerator];
while (object = [e nextObject])
{
NSTableColumn *col = (NSTableColumn*)object;
[resultTableView removeTableColumn:col];
}
}
[resultTableView reloadData];
}
Well, if it's any help you can remove all the columns like this:
- (void)removeAllColumns
{
while([[tableView tableColumns] count] > 0) {
[tableView removeTableColumn:[[tableView tableColumns] lastObject]];
}
}
The NSArray returned by tableColumns is changed by removeTableColumn. Do not assume it is unchanged.
Although it is returned as a non-mutable NSArray, the underlying implementation is being modified and it is not safe to use NSEnumerator with collections that are modified. In the while loop, you are sending a nextObject message to an enumerator whose current object was just deleted -- so bad things can happen!
Here's a more efficient implementation:
NSTableColumn* col;
while ((col = [[tableView tableColumns] lastObject])) {
[tableView removeTableColumn:col];
}
When there are no columns in the table view: tableColumns returns an empty array, lastObject on an empty array returns nil, col is assigned the value of nil, the condition is false and the while loop finishes.
[[[_tableView tableColumns] copy] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[_tableView removeTableColumn:obj];
}];
Here is a Swift implementation:
tableView.tableColumns.forEach({tableView.removeTableColumn($0)})

Check that a input to UITextField is numeric only

How do I validate the string input to a UITextField? I want to check that the string is numeric, including decimal points.
You can do it in a few lines like this:
BOOL valid;
NSCharacterSet *alphaNums = [NSCharacterSet decimalDigitCharacterSet];
NSCharacterSet *inStringSet = [NSCharacterSet characterSetWithCharactersInString:myInputField.text];
valid = [alphaNums isSupersetOfSet:inStringSet];
if (!valid) // Not numeric
-- this is for validating input is numeric chars only. Look at the documentation for NSCharacterSet for the other options. You can use characterSetWithCharactersInString to specify any set of valid input characters.
There are a few ways you could do this:
Use NSNumberFormatter's numberFromString: method. This will return an NSNumber if it can parse the string correctly, or nil if it cannot.
Use NSScanner
Strip any non-numeric character and see if the string still matches
Use a regular expression
IMO, using something like -[NSString doubleValue] wouldn't be the best option because both #"0.0" and #"abc" will have a doubleValue of 0. The *value methods all return 0 if they're not able to convert the string properly, so it would be difficult to distinguish between a legitimate string of #"0" and a non-valid string. Something like C's strtol function would have the same issue.
I think using NSNumberFormatter would be the best option, since it takes locale into account (ie, the number #"1,23" in Europe, versus #"1.23" in the USA).
I use this code in my Mac app, the same or similar should work with the iPhone. It's based on the RegexKitLite regular expressions and turns the text red when its invalid.
static bool TextIsValidValue( NSString* newText, double &value )
{
bool result = false;
if ( [newText isMatchedByRegex:#"^(?:|0|[1-9]\\d*)(?:\\.\\d*)?$"] ) {
result = true;
value = [newText doubleValue];
}
return result;
}
- (IBAction) doTextChanged:(id)sender;
{
double value;
if ( TextIsValidValue( [i_pause stringValue], value ) ) {
[i_pause setTextColor:[NSColor blackColor]];
// do something with the value
} else {
[i_pause setTextColor:[NSColor redColor]];
}
}
If you want a user to only be allowed to enter numerals, you can make your ViewController implement part of UITextFieldDelegate and define this method:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSString *resultingString = [textField.text stringByReplacingCharactersInRange: range withString: string];
// The user deleting all input is perfectly acceptable.
if ([resultingString length] == 0) {
return true;
}
NSInteger holder;
NSScanner *scan = [NSScanner scannerWithString: resultingString];
return [scan scanInteger: &holder] && [scan isAtEnd];
}
There are probably more efficient ways, but I find this a pretty convenient way. And the method should be readily adaptable to validating doubles or whatever: just use scanDouble: or similar.
#pragma mark - UItextfield Delegate
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if ([string isEqualToString:#"("]||[string isEqualToString:#")"]) {
return TRUE;
}
NSLog(#"Range ==%d ,%d",range.length,range.location);
//NSRange *CURRANGE = [NSString rangeOfString:string];
if (range.location == 0 && range.length == 0) {
if ([string isEqualToString:#"+"]) {
return TRUE;
}
}
return [self isNumeric:string];
}
-(BOOL)isNumeric:(NSString*)inputString{
BOOL isValid = NO;
NSCharacterSet *alphaNumbersSet = [NSCharacterSet decimalDigitCharacterSet];
NSCharacterSet *stringSet = [NSCharacterSet characterSetWithCharactersInString:inputString];
isValid = [alphaNumbersSet isSupersetOfSet:stringSet];
return isValid;
}
Here are a few one-liners which combine Peter Lewis' answer above (Check that a input to UITextField is numeric only) with NSPredicates
#define REGEX_FOR_NUMBERS #"^([+-]?)(?:|0|[1-9]\\d*)(?:\\.\\d*)?$"
#define REGEX_FOR_INTEGERS #"^([+-]?)(?:|0|[1-9]\\d*)?$"
#define IS_A_NUMBER(string) [[NSPredicate predicateWithFormat:#"SELF MATCHES %#", REGEX_FOR_NUMBERS] evaluateWithObject:string]
#define IS_AN_INTEGER(string) [[NSPredicate predicateWithFormat:#"SELF MATCHES %#", REGEX_FOR_INTEGERS] evaluateWithObject:string]
For integer test it'll be:
- (BOOL) isIntegerNumber: (NSString*)input
{
return [input integerValue] != 0 || [input isEqualToString:#"0"];
}
You can use the doubleValue of your string like
NSString *string=#"1.22";
double a=[string doubleValue];
i think this will return a as 0.0 if the string is invalid (it might throw an exception, in which case you can just catch it, the docs say 0.0 tho). more info here
Hi had the exact same problem and I don't see the answer I used posted, so here it is.
I created and connected my text field via IB. When I connected it to my code via Control+Drag, I chose Action, then selected the Editing Changed event. This triggers the method on each character entry. You can use a different event to suit.
Afterwards, I used this simple code to replace the text. Note that I created my own character set to include the decimal/period character and numbers. Basically separates the string on the invalid characters, then rejoins them with empty string.
- (IBAction)myTextFieldEditingChangedMethod:(UITextField *)sender {
NSCharacterSet *validCharacterSet = [NSCharacterSet characterSetWithCharactersInString:#".0123456789"];
NSCharacterSet *invalidCharacterSet = validCharacterSet.invertedSet;
sender.text = [[sender.text componentsSeparatedByCharactersInSet:invalidCharacterSet] componentsJoinedByString:#""];
}
Credits:
Remove all but numbers from NSString
Late to the game but here a handy little category I use that accounts for decimal places and the local symbol used for it. link to its gist here
#interface NSString (Extension)
- (BOOL) isAnEmail;
- (BOOL) isNumeric;
#end
#implementation NSString (Extension)
/**
* Determines if the current string is a valid email address.
*
* #return BOOL - True if the string is a valid email address.
*/
- (BOOL) isAnEmail
{
NSString *emailRegex = #"[A-Z0-9a-z._%+-]+#[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}";
NSPredicate *emailTest = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", emailRegex];
return [emailTest evaluateWithObject:self];
}
/**
* Determines if the current NSString is numeric or not. It also accounts for the localised (Germany for example use "," instead of ".") decimal point and includes these as a valid number.
*
* #return BOOL - True if the string is numeric.
*/
- (BOOL) isNumeric
{
NSString *localDecimalSymbol = [[NSLocale currentLocale] objectForKey:NSLocaleDecimalSeparator];
NSMutableCharacterSet *decimalCharacterSet = [NSMutableCharacterSet characterSetWithCharactersInString:localDecimalSymbol];
[decimalCharacterSet formUnionWithCharacterSet:[NSCharacterSet alphanumericCharacterSet]];
NSCharacterSet* nonNumbers = [decimalCharacterSet invertedSet];
NSRange r = [self rangeOfCharacterFromSet: nonNumbers];
if (r.location == NSNotFound)
{
// check to see how many times the decimal symbol appears in the string. It should only appear once for the number to be numeric.
int numberOfOccurances = [[self componentsSeparatedByString:localDecimalSymbol] count]-1;
return (numberOfOccurances > 1) ? NO : YES;
}
else return NO;
}
#end
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if(string.length > 0)
{
NSCharacterSet *numbersOnly = [NSCharacterSet characterSetWithCharactersInString:#"0123456789"];
NSCharacterSet *characterSetFromTextField = [NSCharacterSet characterSetWithCharactersInString:string];
BOOL stringIsValid = [numbersOnly isSupersetOfSet:characterSetFromTextField];
return stringIsValid;
}
return YES;
}
IMO the best way to accomplish your goal is to display a numeric keyboard rather than the normal keyboard. This restricts which keys are available to the user. This alleviates the need to do validation, and more importantly it prevents the user from making a mistake. The number pad is also much nicer for entering numbers because the keys are substantially larger.
In interface builder select the UITextField, go to the Attributes Inspector and change the "Keyboard Type" to "Decimal Pad".
That'll make the keyboard look like this:
The only thing left to do is ensure the user doesn't enter in two decimal places. You can do this while they're editing. Add the following code to your view controller. This code removes a second decimal place as soon as it is entered. It appears to the user as if the 2nd decimal never appeared in the first place.
- (void)viewDidLoad
{
[super viewDidLoad];
[self.textField addTarget:self
action:#selector(textFieldDidChange:)
forControlEvents:UIControlEventEditingChanged];
}
- (void)textFieldDidChange:(UITextField *)textField
{
NSString *text = textField.text;
NSRange range = [text rangeOfString:#"."];
if (range.location != NSNotFound &&
[text hasSuffix:#"."] &&
range.location != (text.length - 1))
{
// There's more than one decimal
textField.text = [text substringToIndex:text.length - 1];
}
}
#property (strong) NSNumberFormatter *numberFormatter;
#property (strong) NSString *oldStringValue;
- (void)awakeFromNib
{
[super awakeFromNib];
self.numberFormatter = [[NSNumberFormatter alloc] init];
self.oldStringValue = self.stringValue;
[self setDelegate:self];
}
- (void)controlTextDidChange:(NSNotification *)obj
{
NSNumber *number = [self.numberFormatter numberFromString:self.stringValue];
if (number) {
self.oldStringValue = self.stringValue;
} else {
self.stringValue = self.oldStringValue;
}
}
Old thread, but it's worth mentioning that Apple introduced NSRegularExpression in iOS 4.0. (Taking the regular expression from Peter's response)
// Look for 0-n digits from start to finish
NSRegularExpression *noFunnyStuff = [NSRegularExpression regularExpressionWithPattern:#"^(?:|0|[1-9]\\d*)(?:\\.\\d*)?$" options:0 error:nil];
// There should be just one match
if ([noFunnyStuff numberOfMatchesInString:<#theString#> options:0 range:NSMakeRange(0, <#theString#>.length)] == 1)
{
// Yay, digits!
}
I suggest storing the NSRegularExpression instance somewhere.
I wanted a text field that only allowed integers. Here's what I ended up with (using info from here and elsewhere):
Create integer number formatter (in UIApplicationDelegate so it can be reused):
#property (nonatomic, retain) NSNumberFormatter *integerNumberFormatter;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Create and configure an NSNumberFormatter for integers
integerNumberFormatter = [[NSNumberFormatter alloc] init];
[integerNumberFormatter setMaximumFractionDigits:0];
return YES;
}
Use filter in UITextFieldDelegate:
#interface MyTableViewController : UITableViewController <UITextFieldDelegate> {
ictAppDelegate *appDelegate;
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
// Make sure the proposed string is a number
NSNumberFormatter *inf = [appDelegate integerNumberFormatter];
NSString* proposedString = [textField.text stringByReplacingCharactersInRange:range withString:string];
NSNumber *proposedNumber = [inf numberFromString:proposedString];
if (proposedNumber) {
// Make sure the proposed number is an integer
NSString *integerString = [inf stringFromNumber:proposedNumber];
if ([integerString isEqualToString:proposedString]) {
// proposed string is an integer
return YES;
}
}
// Warn the user we're rejecting the change
AudioServicesPlayAlertSound(kSystemSoundID_Vibrate);
return NO;
}
Not so elegant, but simple :)
- (BOOL) isNumber: (NSString*)input
{
return [input doubleValue] != 0 || [input isEqualToString:#"0"] || [input isEqualToString:#"0.0"];
}
Accept decimal values in text fields with single (.)dot working with iPad and iPhone in Swift 3
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let inverseSet = NSCharacterSet(charactersIn:"0123456789").inverted
let components = string.components(separatedBy: inverseSet)
let filtered = components.joined(separator: "")
if filtered == string {
return true
} else {
if string == "." {
let countdots = textField.text!.components(separatedBy:".").count - 1
if countdots == 0 {
return true
}else{
if countdots > 0 && string == "." {
return false
} else {
return true
}
}
}else{
return false
}
}
}
To be more international (and not only US colored ;-) ) just replace in the code above by
-(NSNumber *) getNumber
{
NSString* localeIdentifier = [[NSLocale autoupdatingCurrentLocale] localeIdentifier];
NSLocale *l_en = [[NSLocale alloc] initWithLocaleIdentifier: localeIdentifier] ;
return [self getNumberWithLocale: [l_en autorelease] ];
}
This answer uses NSFormatter as said previously. Check it out:
#interface NSString (NSNumber)
- (BOOL) isNumberWithLocale:(NSLocale *) stringLocale;
- (BOOL) isNumber;
- (NSNumber *) getNumber;
- (NSNumber *) getNumberWithLocale:(NSLocale*) stringLocale;
#end
#implementation NSString (NSNumber)
- (BOOL) isNumberWithLocale:(NSLocale *) stringLocale
{
return [self getNumberWithLocale:stringLocale] != nil;
}
- (BOOL) isNumber
{
return [ self getNumber ] != nil;
}
- (NSNumber *) getNumber
{
NSLocale *l_en = [[NSLocale alloc] initWithLocaleIdentifier: #"en_US"] ;
return [self getNumberWithLocale: [l_en autorelease] ];
}
- (NSNumber *) getNumberWithLocale:(NSLocale*) stringLocale
{
NSNumberFormatter *formatter = [[ [ NSNumberFormatter alloc ] init ] autorelease];
[formatter setLocale: stringLocale ];
return [ formatter numberFromString:self ];
}
#end
I hope it helps someone. =)
#import "NSString+Extension.h"
//#interface NSString (Extension)
//
//- (BOOL) isAnEmail;
//- (BOOL) isNumeric;
//
//#end
#implementation NSString (Extension)
- (BOOL) isNumeric
{
NSString *emailRegex = #"[0-9]+";
NSPredicate *emailTest = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", emailRegex];
return [emailTest evaluateWithObject:self];
// NSString *localDecimalSymbol = [[NSLocale currentLocale] objectForKey:NSLocaleDecimalSeparator];
// NSMutableCharacterSet *decimalCharacterSet = [NSMutableCharacterSet characterSetWithCharactersInString:localDecimalSymbol];
// [decimalCharacterSet formUnionWithCharacterSet:[NSCharacterSet alphanumericCharacterSet]];
//
// NSCharacterSet* nonNumbers = [decimalCharacterSet invertedSet];
// NSRange r = [self rangeOfCharacterFromSet: nonNumbers];
//
// if (r.location == NSNotFound)
// {
// // check to see how many times the decimal symbol appears in the string. It should only appear once for the number to be numeric.
// int numberOfOccurances = [[self componentsSeparatedByString:localDecimalSymbol] count]-1;
// return (numberOfOccurances > 1) ? NO : YES;
// }
// else return NO;
}
In Swift 4:
let formatString = "12345"
if let number = Decimal(string:formatString){
print("String contains only number")
}
else{
print("String doesn't contains only number")
}
This covers: Decimal part control (including number of decimals allowed), copy/paste control, international separators.
Steps:
Make sure your view controller inherits from UITextFieldDelegate
class MyViewController: UIViewController, UITextFieldDelegate {...
In viewDidLoad, set your control delegate to self:
override func viewDidLoad() {
super.viewDidLoad();
yourTextField.delegate = self
}
Implement the following method and update the "decsAllowed" constant with the desired amount of decimals or 0 if you want a natural number.
Swift 4
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let decsAllowed: Int = 2
let candidateText = NSString(string: textField.text!).replacingCharacters(in: range, with: string)
let decSeparator: String = NumberFormatter().decimalSeparator!;
let splitted = candidateText.components(separatedBy: decSeparator)
let decSeparatorsFound = splitted.count - 1
let decimalPart = decSeparatorsFound > 0 ? splitted.last! : ""
let decimalPartCount = decimalPart.characters.count
let characterSet = NSMutableCharacterSet.decimalDigit()
if decsAllowed > 0 {characterSet.addCharacters(in: decSeparator)}
let valid = characterSet.isSuperset(of: CharacterSet(charactersIn: candidateText)) &&
decSeparatorsFound <= 1 &&
decsAllowed >= decimalPartCount
return valid
}
If afterwards you need to safely convert that string into a number, you can just use Double(yourstring) or Int(yourstring) type cast, or the more academic way:
let formatter = NumberFormatter()
let theNumber: NSNumber = formatter.number(from: yourTextField.text)!