Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS 13 Crash with SwipeKeyboard and textfield:shouldChangeCharactersIn:

In iOS 13, when implementing shouldChangeCharactersIn via the UITextfieldDelegate, the application crashes when using the swiping keyboard.

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        if let text = textField.text as NSString? {
            let txtAfterUpdate = text.replacingCharacters(in: range, with: string)
            textField.text = txtAfterUpdate
        }
        return false
    }

Is this an Apple bug?

like image 613
mylegfeelsfunny Avatar asked Oct 25 '19 14:10

mylegfeelsfunny


2 Answers

I was able to reproduce this - if you mutate the state of the text on a UITextField during swipe entry - and only during swipe entry, it'll attempt to reinsert the swiped content (even if you return false), which retriggers your delegate event, which kicks off the recursive cycle.

It's a bit of a hack but you could catch it with something like

    private var lastEntry: String?

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        if string.count > 1 && string == lastEntry { // implies we're swiping or pasting
            print("Caught unwanted recursion")
            return
        }
        lastEntry = string
        if let text = textField.text as NSString? {
            let txtAfterUpdate = text.replacingCharacters(in: range, with: string)
            textField.text = txtAfterUpdate
        }
        return false
    }

It'll stop users from pasting/swiping the same thing twice in a row, but at least it'll let them swipe while Apple fixes their problem.

like image 143
mcornell Avatar answered Nov 19 '22 11:11

mcornell


I used UIPasteboard to identify when the user is pasting and then leave the text as the user entered using the swipe like this:

public func textField(_ textField: UITextField,
                      shouldChangeCharactersIn range: NSRange,
                      replacementString string: String) -> Bool {

    //check if the user used swipe keyboard
    if string.count > 1 && string != UIPasteboard.general.string ?? "" {
        return true
    }
    //do the text treatment
    return false
}

I also realized that the TextField only accepts static strings when using swipe keyboard. Hope it Helps.

like image 40
lcruz Avatar answered Nov 19 '22 10:11

lcruz