-1

So I successfully implemented the solution to limit the size of a UITextField in the following link Max length UITextField However, I cannot understand why you must use

var newLength = countElements(textField.text) + countElements(string) - range.length
return !(newLength > 5)

instead of my initial solution of

var newLength = countElements(textField.text)
return !(newLength > 4)

Both solutions limit the string size to 5 digits in the UITextField, but the first solution allows the user to use the backspace to delete characters, but the second solution (my initial solution) does not allow the user to use the backspace to delete characters. Can somebody please explain?

Community
  • 1
  • 1
  • It would be extraordinarily helpful if this question included the context in which this code is in. What are you `return`-ing from? – nhgrif Apr 02 '15 at 01:34
  • this is an assignment where I am using a text field that should be limited to only 5 digits (a zip code), its more a lesson in using delegates, but I'd rather understand a usable scenario (being able to correct your typo) than just knowing how to set a delegate – Brian Josel Apr 02 '15 at 15:07
  • Yes, but **which** delegate method this logic is being applied in is crucially relevant to explaining the scenario. That said, I think my answer sufficiently explains it based on an assumption of the delegate method this logic is in. – nhgrif Apr 02 '15 at 15:10
  • I'm sorry, yes the correct delegate method I was using was `textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool` – Brian Josel Apr 02 '15 at 15:50

2 Answers2

2

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.

nhgrif
  • 61,578
  • 25
  • 134
  • 173
  • this was great, thanks! I think the biggest revelation is that `textField.text` is not what is presented in the text window in the UI, its the string that was presented prior to the user asking to input another character to the UI. Some `println()` messages show this (e.g. `countElements(textField.text)` does not change value just because you hit backspace since its the count of the previous output to the UI prior to a character entered or removed, therefore the Bool can't change back to `true` to allow for a change) – Brian Josel Apr 02 '15 at 15:25
0

You have many escenarios to consider, for example, you could select a range of text and then replace it for many characters or even none, that's why you need to evaluate:

  1. the characters in the TextField
  2. the characters that will be added to the textfield (could be more than one character, you could paste what you have in the clipboard)
  3. substract the characters that are going to be replaced (the selected text).

Hope this helps.

Dario
  • 3,105
  • 1
  • 17
  • 16