swiftuitextfielddelegatenscharacterset

UITextFieldDelegate's shouldChangeCharactersIn method - why cannot combine conditional statements checking both # of decimal separators and letters


Why does my replacementTextHasLetter constant not prevent me from pasting in a letter into my textfield with the below conditional?

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

    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 && replacementTextHasLetter != nil {

        return false

    }

    return true

}

But when it has its own separate conditional it works?

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

    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

}

EDIT: I figured it out. It's impossible for the first example to work since existingTextHasDecimalSeparator & replacementTextHasDecimalSeparator are basically determining if there is a decimal in the textfield and if the user is trying to enter a new one, to return false. When I add

&& replacementTextHasLetter != nil

to the conditional, it is just not really serving a purpose since all of the statements can't be true at the same time. Thank you @sonofabeach


Solution

  • These two lines:

    if existingTextHasDecimalSeparator != nil && replacementTextHasDecimalSeparator != nil {
        return false
    }
    
    if replacementTextHasLetter != nil {
        return false
    }
    

    Are the effectively the same as:

    if (existingTextHasDecimalSeparator != nil && replacementTextHasDecimalSeparator != nil) || replacementTextHasLetter != nil {
        return false
    }
    

    Note the use of || instead of && for the last condition.