Disable Alphabetic Characters in a Text Field (Part of my code will not execute) - ios

To prevent the user from inputting more than one decimal into the text field and to prevent the user from inputting alphabetical characters into the text field I have tried the code below. The problem is I don't know how to check them both within the function and have two If statements which means the second one won't run as it never gets executed. If I take the code that checks number of decimals out and leave the character checker code it works perfectly. How can I get them both working though?
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let existingTextHasDecimalSeparator = textField.text?.rangeOfString(".")
let replacementTextHasDecimalSeparator = string.rangeOfString(".")
let charactersNotAllowed = NSCharacterSet.letterCharacterSet()
let replacementTextHasLetter = string.rangeOfCharacterFromSet(charactersNotAllowed)
if existingTextHasDecimalSeparator != nil && replacementTextHasDecimalSeparator != nil {
return false
} else {
return true
}
if replacementTextHasLetter != nil {
return false
} else {
return true
}
}

For swift 4 users you could delete the if replacementTextHasLetter != nil condition thats nested in the first condition along with the else condition and the code would work as well:
let existingTextHasDecimalSeparator = textField.text?.range( of: ".")
let replacementTextHasDecimalSeparator = string.range( of: ".")
let charactersNotAllowed = NSCharacterSet.letters
let replacementTextHasLetter = string.rangeOfCharacter(from: charactersNotAllowed)
if existingTextHasDecimalSeparator != nil, replacementTextHasDecimalSeparator != nil{
return false
}
if replacementTextHasLetter != nil{
return false
}
return true
}

The reason your function does not work is that it makes its decision early for both the positive and the negative case.
Defer returning true to the very end of the function:
if existingTextHasDecimalSeparator != nil && replacementTextHasDecimalSeparator != nil {
// Do not allow multiple decimal separators
return false
}
if replacementTextHasLetter != nil {
// Do not allow letters
return false
}
return true
This reflects the all-or-nothing logic of the decision: all checks must succeed in order to all checks, while it takes only one failed check to reject the change.

let existingTextHasDecimalSeparator = textField.text?.range( of: ".")
let replacementTextHasDecimalSeparator = string.range( of: ".")
let charactersNotAllowed = NSCharacterSet.letters
let replacementTextHasLetter = string.rangeOfCharacter(from: charactersNotAllowed)
if existingTextHasDecimalSeparator != nil, replacementTextHasDecimalSeparator != nil{
if replacementTextHasLetter != nil{
return false
}
return false
} else {
if replacementTextHasLetter != nil{
return false
}
return true
}
Could improve like the one above, but it's how I got my app to not allow multiple decimals and characters. It works.

Related

What does mobile network code of 65535 mean with CTTelephonyNetworkInfo().subscriberCellularProvider?.mobileNetworkCode?

I'm looking at some code somebody else has written which has no documentation, why is this code making a comparison with 65535?
class func canMakePhoneCall() -> Bool
{
guard let URL = URL(string: "tel://") else {
return false
}
let canOpenURL = UIApplication.shared.canOpenURL(URL)
if canOpenURL == false
{
return false
}
let mobileNetworkCode = CTTelephonyNetworkInfo().subscriberCellularProvider?.mobileNetworkCode
let isInvalidNetworkCode = mobileNetworkCode == nil
|| mobileNetworkCode?.characters.count == 0
|| mobileNetworkCode == "65535"
return isInvalidNetworkCode == false
}
According to an answer here, this could be an indication of removed SIM card, or in general inability to make a call at the moment.

Email Validation is wrong as per Regex

I am using email validation into my project which method is like below
//MARK: isValidEmailID
func isValidEmail(testStr:String) -> Bool {
print("validate emilId: \(testStr)")
let emailRegEx = "^(?:(?:(?:(?: )*(?:(?:(?:\\t| )*\\r\\n)?(?:\\t| )+))+(?: )*)|(?: )+)?(?:(?:(?:[-A-Za-z0-9!#$%&’*+/=?^_'{|}~]+(?:\\.[-A-Za-z0-9!#$%&’*+/=?^_'{|}~]+)*)|(?:\"(?:(?:(?:(?: )*(?:(?:[!#-Z^-~]|\\[|\\])|(?:\\\\(?:\\t|[ -~]))))+(?: )*)|(?: )+)\"))(?:#)(?:(?:(?:[A-Za-z0-9](?:[-A-Za-z0-9]{0,61}[A-Za-z0-9])?)(?:\\.[A-Za-z0-9](?:[-A-Za-z0-9]{0,61}[A-Za-z0-9])?)*)|(?:\\[(?:(?:(?:(?:(?:[0-9]|(?:[1-9][0-9])|(?:1[0-9][0-9])|(?:2[0-4][0-9])|(?:25[0-5]))\\.){3}(?:[0-9]|(?:[1-9][0-9])|(?:1[0-9][0-9])|(?:2[0-4][0-9])|(?:25[0-5]))))|(?:(?:(?: )*[!-Z^-~])*(?: )*)|(?:[Vv][0-9A-Fa-f]+\\.[-A-Za-z0-9._~!$&'()*+,;=:]+))\\])))(?:(?:(?:(?: )*(?:(?:(?:\\t| )*\\r\\n)?(?:\\t| )+))+(?: )*)|(?: )+)?$"
let emailTest = NSPredicate(format:"SELF MATCHES %#", emailRegEx)
let result = emailTest.evaluateWithObject(testStr)
return result
}
OR
func isValidEmailID(email: String) -> Bool {
let regExPattern: String = "[A-Z0-9a-z._%+-]+#[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"
let emailValidator: NSPredicate = NSPredicate(format: "SELF MATCHES %#", regExPattern)
let isValid: Bool = emailValidator.evaluateWithObject(email)
return isValid
}
This both Regex works fine when I enter "modijecky#gmail.com" or any other wrong input but it will not work when I enter "modijecky#gmail.com.com".
So,I find out that "name#.com.com" is a valid email address and there are more sub-domains like this. So now I want user not to enter sub-domains. Is there any REGEX that validate email address within just one domain like "name#gmail.com" not with multiple domains or sub-domains.
I also try different Regex from google and implement it into project but same problem occurs.
Please help me with it.
Thank you
Don’t reinvent the wheel:
Not Reinventing the Wheel: Email Validation in Swift
Basically you can use NSDataDetector to do the heavy lifting and have everything consistent and updated to the way it works in macOS and iOS natively. Not only that but you also avoid regex headaches.
// Simplifying the example from the website a bit
import Foundation
func validate(_ text: String) -> Bool {
let types = NSTextCheckingResult.CheckingType.link.rawValue
guard
let dataDetector = try? NSDataDetector(types: types),
let match = dataDetector
.matches(in: text, options: [], range: NSRangeFromString(text))
.first,
let absoluteString = match.url?.absoluteString
else { return false }
return absoluteString == "mailto:\(text)"
}
validate("test#gmail.com") // -> true
validate(" test#gmail.com") // -> false
This will make sure that the entire text is a single, valid email address without any superfluous characters.
Function Call:
let result = isValidEmail(testStr: "test#test.com.op")
if (result)
{
print ("passed")
}
else{
print ("failed")
}
Function Definition:
func isValidEmail(testStr:String) -> Bool {
// print("validate calendar: \(testStr)")
var returnValue : Bool = false
let emailRegEx = "[A-Z0-9a-z._%+-]+#[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"
let emailTest = NSPredicate(format:"SELF MATCHES %#", emailRegEx)
if (emailTest.evaluate(with: testStr))
{
let fullNameArr = testStr.components(separatedBy: "#")
let IdName = fullNameArr[0]
let domainName = fullNameArr[1]
var number = 0
let string = domainName
for character in domainName.characters {
if character == "."
{
number = number + 1
}
}
if number <= 1
{
returnValue = true
}
}
return returnValue
}
Result:
you should have this code to don't allow subdomain.
func isValidEmail(email:String) -> Bool {
if email.range(of: "#") == nil || email.range(of: ".") == nil{
return false
}
let accountName = email.substring(to: email.range(of: "#")!.lowerBound)
let domainName = email.substring(from: email.range(of: "#")!.upperBound)
let subDomain = domainName.substring(from: email.range(of: ".")!.lowerBound)
//filter for user name
let unWantedInUName = " ~!##$^&*()={}[]|;’:\"<>,?/`";
//filter for domain
let unWantedInDomain = " ~!##$%^&*()={}[]|;’:\"<>,+?/`";
//filter for subdomain
let unWantedInSub = " `~!##$%^&*()={}[]:\";’<>,?/1234567890";
//subdomain should not be less that 2 and not greater 6
if(!(subDomain.characters.count>=2 && subDomain.characters.count<=6)) {
return false;
}
if (accountName == "" || accountName.rangeOfCharacter(from: CharacterSet.init(charactersIn: unWantedInUName)) != nil || domainName == "" || domainName.rangeOfCharacter(from: CharacterSet.init(charactersIn: unWantedInDomain)) != nil || subDomain == "" || subDomain.rangeOfCharacter(from: CharacterSet.init(charactersIn: unWantedInSub)) != nil ) {
return false
}
return true
}

swift - sort an array of objects by their optional boolean property without force unwrapping

I can sort this array of store objects by their 'flagship' boolean property, but how can I safely unwrap the 'flagship' property first?
let flagshipStores = self.stores.sort {
$0.flagship! && !$1.flagship!
}
let flagshipStores = self.stores.sort {
guard let flagship0 = $0.flagship, let flagship1 = $1.flagship else { return false }
return flagship0 && !flagship1
}
One more approach: turn the Bool? into an Int, then compare the Ints. You get to specify how a nil value compares to non-nil values.
For instance, this sorts nil values before both false and true:
stores.sort { Int($0.flagship ?? -1) < Int($1.flagship ?? -1) }
This sorts nil values after both false and true:
stores.sort { Int($0.flagship ?? 2) < Int($1.flagship ?? 2) }
You can use the same pattern to make nil compare the same as true or the same as false. It's up to you.
Here's another approach.
You can use flatMap which will remove nil objects and unwrap those that are present. Then, the force unwrap will be safe to sort:
let flagshipStores = stores.flatMap({ return $0.flagship ? $0 : nil }).sort {
$0.flagship! && !$1.flagship!
}
This will remove stores with a nil flagship from the array.
How about:
$0.flagship == true && $1.flagship != true
The left side will succeed if the value is not nil and is true, the right side will succeed if the value is either nil or false.
As mr.Fixit pointed out on a comment, the accepted answer doesn't fully work because it doesn't take care of nils. Here is the correct answer with an extra string sample.
SWIFT 4
for a boolean sorting
let flagshipStores = self.stores.sorted(by: {
guard let flagship0 = $0.flagship, let flagship1 = $1.flagship else {
if $0.flagship == nil && $1.flagship == nil || $0.flagship != nil && $1.flagship == nil{
return true
}
else {
return false
}
}
return ($0.flagship == $1.flagship || $0.flagship == true && $1.flagship == false ? true : false)
})
for strings comparison sorting
let stores = self.stores.sorted(by: {
guard let store0 = $0.store, let store1 = $1.store else {
if $0.store == nil && $1.store == nil || $0.store != nil && $1.store == nil{
return true
}
else {
return false
}
}
return ( ($0.store)?.localizedStandardCompare($1.store!) == ComparisonResult.orderedAscending )
})
To filter nil values just use compactMap before sort
let flagshipStores = self.stores.compactMap { return $0.flagship }.sorted {
$0 && !$1
}
You could use this function to compare the Optional values without the need to unwrap.
func sortOptionalValues<T: Comparable>(lhs: T?, rhs: T?) -> Bool? {
switch (lhs != nil, rhs != nil) {
case (false, false):
return nil
case (true, false):
return true
case (false, true):
return false
case (true, true):
guard let lhs = lhs, let rhs = rhs else { return nil }
return lhs < rhs
}
}

swift multiple conditions if statement with && operation [duplicate]

This question already has answers here:
Checking if text fields are empty cause error in Swift 2
(2 answers)
Closed 6 years ago.
I have 4 text boxes.I don't want to allow user to let all these 4 textfields empty. How can I check multiple conditions in swift. I did like this but it's giving me an error
if self.txtIncomeAd.text?.isEmpty && self.txtIncomeRec.text?.isEmpty &&
like wise. What is the correct way I can do this?
Please help me.
Thanks
you can simply use isEmpty property.
if !self.textFieldOne.text!.isEmpty && !self.textFieldTwo.text!.isEmpty && !self.textFieldThree.text!.isEmpty && !self.textFieldFour.text!.isEmpty {
...
}
or you can also safely unwrap the text value and the check that it is empty of not
if let text1 = self.textFieldOne.text, text2 = self.textFieldTwo.text, text3 = self.textFieldthree.text,text4 = self.textFieldFour.text where !text1.isEmpty && !text2.isEmpty && !text3.isEmpty && !text4.isEmpty {
...
}
Or you can compare with Empty "" String
if self.textFieldOne.text != "" && self.textFieldTwo.text != "" && self.textFieldThree.text != "" && self.textFieldFour.text != "" {
...
}
and we can also do this with Guard
guard let text = self.myTextField.text where !text.isEmpty else {
return
}
if !self.txtIncomeAd.text!.isEmpty && !self.txtIncomeRec.text!.isEmpty && !self.txtIncomeAd.text!.isEmpty && !self.txtIncomeRec.text!.isEmpty
{
...
}
It gives you an error because the text in the textField is optional. First you have to unwrap them all.
if let txtIncomeAd = self.txtIncomeAd.text,
let txtIncomeRec = self.txtIncomeRec.text {
if txtIncomeAd.isEmpty && txtIncomeRec.isEmpty {
// Do Something
}
} else {
// Empty text field
}
You can check with isEmpty boolean property.
if ((inputTextField.text?.isEmpty) != nil && (inputTextField1.text?.isEmpty)!= nil && (inputTextField2.text?.isEmpty)!=nil) {
}
or
if ((inputTextField.text?.isEmpty)! && (inputTextField1.text?.isEmpty)! && (inputTextField2.text?.isEmpty)!) {
}
Here's something a bit different:
extension UILabel {
var textIsEmpty: Bool { return text?.isEmpty ?? true }
}
class MyClass: UIView {
let txtIncomeAd = UILabel()
let txtIncomeRec = UILabel()
var textFieldsAreNonEmpty: Bool {
return ![txtIncomeAd, txtIncomeRec].contains { $0.textIsEmpty }
}
}
let c = MyClass()
c.txtIncomeAd.text = "hello"
c.txtIncomeRec.text = "there"
if c.textFieldsAreNonEmpty {
print("text fields are valid")
}

Check the valid phone number

I have one text field for enter the phone number and user have to press OK button.
Then I write some function to check whether entered number is valid number or 10 digit number. And I don't want to add country code. That I have separately.
But when I press OK button its give me uialert - wrong number for all number including my own number. I don't know any code I missed?
func validate(value: String) -> Bool {
let PHONE_REGEX = "^\\d{3}-\\d{3}-\\d{4}$"
var phoneTest = NSPredicate(format: "SELF MATCHES %#", PHONE_REGEX)
var result = phoneTest.evaluateWithObject(value)
return result
}
#IBAction func confirmAction(sender: AnyObject) {
if validate(phoneNumber.text!)
{
print("Validate EmailID")
let phone = countryCode.text! + phoneNumber.text!
UserNetworkInterface().generateSms(phone, onCompletion: nil)
performSegueWithIdentifier("ConfirmSmsCode", sender: self)
}
else
{
print("invalide EmailID")
let alert = UIAlertView()
alert.title = "Message"
alert.message = "Enter Valid Contact Number"
alert.addButtonWithTitle("Ok")
alert.delegate = self
alert.show()
}
}
Updated :
#IBAction func confirmAction(sender: AnyObject) {
if let phoneNumberValidator = phoneNumber.isPhoneNumber
{
print("Validate EmailID")
let phone = countryCode.text! + phoneNumber.text!
UserNetworkInterface().generateSms(phone, onCompletion: nil)
performSegueWithIdentifier("ConfirmSmsCode", sender: self)
}
else
{
print("invalide EmailID")
let alert = UIAlertView()
alert.title = "Message"
alert.message = "Enter Valid Contact Number"
alert.addButtonWithTitle("Ok")
alert.delegate = self
alert.show()
phoneNumber.text = ""
}
// Number valid
}
Try this.
Make an extension to String.
Swift 4
extension String {
var isPhoneNumber: Bool {
do {
let detector = try NSDataDetector(types: NSTextCheckingResult.CheckingType.phoneNumber.rawValue)
let matches = detector.matches(in: self, options: [], range: NSRange(location: 0, length: self.count))
if let res = matches.first {
return res.resultType == .phoneNumber && res.range.location == 0 && res.range.length == self.count
} else {
return false
}
} catch {
return false
}
}
}
Older Swift Versions
extension String {
var isPhoneNumber: Bool {
do {
let detector = try NSDataDetector(types: NSTextCheckingType.PhoneNumber.rawValue)
let matches = detector.matchesInString(self, options: [], range: NSMakeRange(0, self.characters.count))
if let res = matches.first {
return res.resultType == .PhoneNumber && res.range.location == 0 && res.range.length == self.characters.count
} else {
return false
}
} catch {
return false
}
}
}
Usage:
override func viewWillAppear(animated: Bool) {
//Sample check
let phoneString = "8888888888"
let phoneNumberValidator = phoneString.isPhoneNumber
print(phoneNumberValidator)
}
Swift 3
For those of you who would like the phone number to have a minimum of 10 characters use the below code (Amended #Alvin George code)
extension String {
var isPhoneNumber: Bool {
do {
let detector = try NSDataDetector(types: NSTextCheckingResult.CheckingType.phoneNumber.rawValue)
let matches = detector.matches(in: self, options: [], range: NSMakeRange(0, self.characters.count))
if let res = matches.first {
return res.resultType == .phoneNumber && res.range.location == 0 && res.range.length == self.characters.count && self.characters.count == 10
} else {
return false
}
} catch {
return false
}
}
}
Usage
ooverride func viewDidLoad() {
super.viewDidLoad()
//Example
let phoneNumberString = "8500969696"
let phoneNumberValidation = phoneNumberString.isPhoneNumber
print(phoneNumberValidation)
// Prints: true
}
Try this for Indian 10 digit mobile number validation
var isValidMobileNo: Bool {
let PHONE_REGEX = "^[7-9][0-9]{9}$";
let phoneTest = NSPredicate(format: "SELF MATCHES %#", PHONE_REGEX)
let result = phoneTest.evaluate(with: self)
return result
}
Amended #Alvin George code for Swift 4 that also accepts only 10 digit phone numbers:
extension String {
var isPhoneNumber: Bool {
do {
let detector = try NSDataDetector(types: NSTextCheckingResult.CheckingType.phoneNumber.rawValue)
let matches = detector.matches(in: self, options: [], range: NSMakeRange(0, self.count))
if let res = matches.first {
return res.resultType == .phoneNumber && res.range.location == 0 && res.range.length == self.count && self.count == 10
} else {
return false
}
} catch {
return false
}
}
}
Easy validation for Indian 10 digit mobile number
func isValidPhone(testStr:String) -> Bool {
let phoneRegEx = "^[6-9]\\d{9}$"
var phoneNumber = NSPredicate(format:"SELF MATCHES %#", phoneRegEx)
return phoneNumber.evaluate(with: testStr)
}
Modifying #A.G's answer to update to Swift 5:
extension String {
func isValidPhone() -> Bool {
do {
let detector = try NSDataDetector(types: NSTextCheckingResult.CheckingType.phoneNumber.rawValue)
let matches = detector.matches(in: self, options: [], range: NSMakeRange(0, self.count))
if let res = matches.first {
return res.resultType == .phoneNumber && res.range.location == 0 && res.range.length == self.count
} else {
return false
}
} catch {
return false
}
}
}

Resources