Simple? Bronze Solution

I have tried to make it as simple as I possibly could and have treated them as separate events.

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    let allowedCharacterSet = CharacterSet(charactersIn: "0123456789.")
    let existingTextHasDecimalSeparator = textField.text?.range(of: ".")
    let replacementTextHasDecimalSeparator = string.range(of: ".")
    for i in string.unicodeScalars {
        if allowedCharacterSet.contains(i) == false {
            return false
    if existingTextHasDecimalSeparator != nil, replacementTextHasDecimalSeparator != nil {
        return false
    } else {
        return true

Hope this helps you guys!

Work properly, almost I obtain the same answer than you. Great job!!

Nice solution,

suggestion, change this:
allowedCharacterSet.contains(i) == false