Tom
Tom

Reputation: 802

Swift Form Validation - Check if Int or String has been entered

I am trying to validate a form to make sure the user has entered an integer number and not a string. I can check if the number is an integer as follows:

 var possibleNumber = timeRetrieved.text
    convertedNumber = possibleNumber.toInt()
    // convertedNumber is inferred to be of type "Int?", or "optional Int"

    if convertedNumber != nil {

        println("It's a number!")

        totalTime = convertedNumber!


    }

My problem is I want to make sure the user has not entered any text, doubles etc. I only want integer numbers. The following code does not work because it evaluates true if the variable is an integer. What code should I use to evaluate if variable is not an integer?

if convertedNumber != nil  {


        let alertController = UIAlertController(title: "Validation Error", message: "You must enter an integer number!", preferredStyle: .Alert)
        let alertAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.Destructive, handler: {(alert : UIAlertAction!) in
            alertController.dismissViewControllerAnimated(true, completion: nil)
        })
        alertController.addAction(alertAction)
        presentViewController(alertController, animated: true, completion: nil)

Upvotes: 2

Views: 16949

Answers (6)

Mobile Dan
Mobile Dan

Reputation: 7134

Int initializer

This works in Swift 2.2 and above. It is based on Minhal Khan's answer which illustrates that Int has an initializer with this signature: init?(_ text: String, radix: Int = default). Since radix has a default value, it can be left out. *more info on this initializer is found here.

var totalTime: Int?
let possibleInt = timeRetrieved.text ?? ""
if let convertedNumber = Int(possibleInt) {
    print("'\(possibleInt)' is an Int")
    totalTime = convertedNumber
}
else {
    print("'\(possibleInt)' is not an Int")
}

print("totalTime: '\(totalTime)'")

Note: I assumed timeRetrieved is a UITextField. The UITextField text property is an optional string (though programmatically not allowed to be nil). Therefore, the compiler requires it be unwrapped. I used the nil coalescing operator (??) to substitute a nil for empty string which does not yield an integer as desired. Here's a post that discusses the optionality of UITextfield.text.

Upvotes: 2

Mario
Mario

Reputation: 3379

Based on @Graham Perks answer a Swift 3 Version as string extension:

extension String
{
    var isNumeric: Bool
    {
        let range = self.rangeOfCharacter(from: CharacterSet.decimalDigits.inverted)
        return (range == nil)
    }
}

Usage:

"123".isNumeric // true
"abc".isNumeric // false

Upvotes: 1

Minhal Khan
Minhal Khan

Reputation: 321

What i had done was get the value and check if it could convert it, works for me

var enteredText = Int(textfield.text) 
if enteredText == nil{
    //String entered 
} 
else{
//Int entered
}

Upvotes: 1

Graham Perks
Graham Perks

Reputation: 23398

Swift 2 changes this: as both Int("abc") and Int("0") return 0, integer conversion can't be used. You could use this:

class Validation {
    static func isStringNumerical(string : String) -> Bool {
        // Only allow numbers. Look for anything not a number.
        let range = string.rangeOfCharacterFromSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet)
        return (range == nil)
    }
}

It uses a decimalDigitCharacterSet, and can be changed to use whatever character set you want.

func testIsStringNumerical() {
    XCTAssertEqual(SignUpLoyaltyViewController.isStringNumerical("123"), true)
    XCTAssertEqual(SignUpLoyaltyViewController.isStringNumerical(""), true)
    XCTAssertEqual(SignUpLoyaltyViewController.isStringNumerical("12AA"), false)
    XCTAssertEqual(SignUpLoyaltyViewController.isStringNumerical("123.4"), false)
}

This is dramatically faster than the Regex answer. (2000 runs, 0.004s vs regex 0.233s)

Timing from device

Upvotes: 5

JohnVanDijk
JohnVanDijk

Reputation: 3581

I really recommend using a REGEX, I was recently trying to validate 10 digit phone numbers using if let _ = Int(stringToTest)... and on 32 bit hardware, I faced range issues.

func validate(value: String) -> Bool {
  let PHONE_REGEX = "\\d{10}"
  let phoneTest = NSPredicate(format: "SELF MATCHES %@", PHONE_REGEX)
  let result =  phoneTest.evaluateWithObject(value)
  if result == true {
    log.info("'\(self.text!)' is a valid number.")
  } else {
    log.info("'\(self.text!)' is an invalid number.")
  }
  return result
}

Upvotes: 0

Marnix999L
Marnix999L

Reputation: 81

If the number the user has entered is not an integer, convertedNumber will be nil. Just add an else clause in which you can show the alert.

Upvotes: 4

Related Questions