iOS 13使用SwipeKeyboard和textfield崩溃:shouldChangeCharactersIn:

时间:2019-10-25 14:50:02

标签: ios uitextfield ios13

在iOS 13中,通过shouldChangeCharactersIn实现UITextfieldDelegate时,使用滑动键盘时应用程序崩溃。

    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
    }

这是Apple的错误吗?

3 个答案:

答案 0 :(得分:2)

我能够重现此内容-如果您在滑动输入期间更改了UITextField上文本的状态-并且仅在滑动输入期间,它将尝试重新插入滑动的内容(即使您返回false),也会重新触发您的委托事件,这将启动递归循环。

这有点hack,但是您可以用

来捕获它
    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
    }

这将阻止用户连续两次粘贴/滑动相同的东西,但至少在Apple解决问题时,至少可以让用户滑动。

答案 1 :(得分:0)

我使用UIPasteboard识别用户何时粘贴,然后将文本保留为用户使用如下滑动输入的内容:

myFunction()

我还意识到,使用滑动键盘时,TextField仅接受静态字符串。 希望对您有所帮助。

答案 2 :(得分:0)

在设置文本之前,您可以重置委托,然后再次将其设置为 self。 但是如果 textfield 为空,这个解决方案有一个问题 - 文本会翻倍。

Му 代码示例:

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    let currentText: String = textField.text ?? ""
    if #available(iOS 13, *) {
        textField.delegate = nil
        let resultText = editedText
        textField.text = resultText
        if currentText.isEmpty, textField.text != resultText {
            textField.text = resultText
        }
        textField.delegate = self
    } else {
        textField.text = input.result
    }
    return false
}