2

Question: For some reason in the TextField Delegate method shouldChangeCharactersInRange the range.length is always 0...

My Code

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
        var shouldChange = true
        let newSubjectString = (textField.text! as NSString).stringByReplacingCharactersInRange(range, withString: string)
        let newCharacters = NSCharacterSet(charactersInString: newSubjectString as String)
        let currentCharacterCount = textField.text?.utf16.count ?? 0
        if (range.length + range.location > currentCharacterCount){
            return false
        }

        if newSubjectString.lengthOfBytesUsingEncoding(NSUTF8StringEncoding) >= 3 {
            return false
        }
        return true
}

I am trying to get rid of the "Undo Bug" (When paste doesn't pass my validation then i try to shake, to Undo, and then the app crashes).. though whenever I check the range.length in this function.. it is always 0. Though this same fix did work in other areas of my app.

To clarify... it is not a crash that I am looking to fix... the fix for the crash is supposed to be the following lines(Which work in other places of my app):

let currentCharacterCount = textField.text?.utf16.count ?? 0
if (range.length + range.location > currentCharacterCount){
    return false
}

The issue I am having is that in a specific controller when using the ^ sanity check.. it is not always accurate because range.length is always 0 in this delegate method.

A note on the crashing "undo" bug

As is mentioned in the comments, there is a bug with UITextField that can lead to a crash.

If you paste in to the field, but the paste is prevented by your validation implementation, the paste operation is still recorded in the application's undo buffer. If you then fire an undo (by shaking the device and confirming an Undo), the UITextField will attempt to replace the string it thinks it pasted in to itself with an empty string. This will crash because it never actually pasted the string in to itself. It will try to replace a part of the string that doesn't exist.

Fortunately you can protect the UITextField from killing itself like this. You just need to ensure that the range it proposes to replace does exist within its current string. This is what the initial sanity check above does.

Any help is much appreciated :)

Community
  • 1
  • 1
JoellyR
  • 153
  • 1
  • 17
  • 1
    It's length will be different from 0 if you select some text with long press and press any letter on the keyboard. – alexburtnik Nov 09 '16 at 21:08
  • You need to provide more details about the crash. Which line exactly causes the crash? What is the error of the crash? – rmaddy Nov 09 '16 at 21:10
  • 2
    It is not so much the crash i am worried about.. as the following lines usually take care of it: `let currentCharacterCount = textField.text?.utf16.count ?? 0 if (range.length + range.location > currentCharacterCount){ return false}` I am more concerned about why the range.length is always 0 no matter what text i type in – JoellyR Nov 09 '16 at 21:29
  • 1
    Though if you do want to know the crash i added that check for it is: `*** Terminating app due to uncaught exception 'NSRangeException', reason: '-[__NSCFString replaceCharactersInRange:withString:]: Range or index out of bounds'` it seems to be coming from the `let newSubjectString = (textField.text! as NSString).stringByReplacingCharactersInRange(range, withString: string)` again this probably has to do with the range length being 0 – JoellyR Nov 09 '16 at 21:31
  • 1
    I suggest you read through some of the answers at http://stackoverflow.com/questions/25138339/nsrange-to-rangestring-index – rmaddy Nov 09 '16 at 21:41
  • sadly there doesn't seem to be anything in regards to my issue in that post :( – JoellyR Nov 10 '16 at 16:53

0 Answers0