This was answered for text fields by @whyceewhite several years ago. One approach is to use the NumberFormatter() to determine if the value is a a valid number.
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        let numberFormatter = NumberFormatter()
        numberFormatter.numberStyle = .decimal
        return numberFormatter.number(from: textView.text + text) != nil
    }
Perhaps you also want to handle the case when a user enters a decimal as the first value of a number, which will return nil when put into number formatter. You can use something as follows:
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        if (textView.text == nil || textView.text == "") && text == "." {
            textView.text = "0"
            return true
        } else {
            let numberFormatter = NumberFormatter()
            numberFormatter.numberStyle = .decimal
            return numberFormatter.number(from: textView.text + text) != nil
        }
    }
Which will check if the text field text is nil or empty and that the value to be inserted is a ., add a leading zero and then add the decimal.