Assuming the snippets in the question are extracted from this UITextFieldDelegate
method:
textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
The problem becomes pretty clear when you realize that Apple tries to make their method names plain-English readable. This method is called should change characters. The verb tense of the method name implies that this method is called before the text field's characters are changed. And it returns a Bool
. It's asking us whether or not it should change the characters.
Importantly, this means that whatever textField.text
is, it hasn't taken account for the change the user is attempting to make yet. Equally important, this method is called when the user is pressing the delete/backspace key as well as when the user as selected a range of text and is pasting something new in.
So, why does your second method fail in certain scenarios?
Your goal is assure that the maximum length is a certain number of characters, correct? If we press the backspace key, our delegate method will be called with a range of last index and length of 1 (we're deleting the last character), and the string
argument will be an emptry string: ""
. If we return true
, the string's length will be one character shorter.
But keep in mind, textField.text
still holds the same value it did before the user pressed a button at this point. Your approach will look at the length, see that the string is already at the maximum length, and disallow ALL changes because your approach assumes that any call to shouldChangeCharactersInRange
means the length in increasing, but that simply isn't the case.
The alternate approach calculates what the length would be if we were to return true
to this method and based on that calculation, it returns true or false appropriately.
Effectively, the length
part of the range
variable is the number of characters the user is removing from textField.text
, and the length
part of the string
variable is the number of characters the user is adding to the textField.text
.