If you handle textField(_:shouldChangeCharactersIn:replacementString:)
and return false for a paste operation, once user does and "shake to undo" the provided range is out of bounds of the text field's text. Is this expected?
Here is a sample code that simply limits the input to 5 characters:
class ViewController: UIViewController, UITextFieldDelegate {
@IBOutlet weak var textField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
textField.delegate = self
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let text = textField.text ?? ""
let currentString = text as NSString
let newString = currentString.replacingCharacters(in: range, with: string)
return newString.count < 5
}
}
Steps to reproduce a the crash:
UsernameTextFieldShake[40533:8359309] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString replaceCharactersInRange:withString:]: Range or index out of bounds'
- Type "test"
- Copy the text
- Paste the text at the end of the text field's text
- The paste will not be allowed as it is above 5 length.
- Shake the device
- Press undo
- Crash, due to
let newString = currentString.replacingCharacters(in: range, with: string)
Is there a correct way to guard agains this "rogue" range?
Is this range expected to be provided to the textField(_:shouldChangeCharactersIn:replacementString:)
, one might think because the previous handling returned false
that the undo should happen on the previous accepted command (which was at step 1)
Thank you for the responses.