iOS 键盘 : textDocumentProxy. documentContextBeforeInput.isEmpty 意外返回 Nil(当它不应该返回时)

标签 ios swift custom-keyboard

我正在使用自定义 iOS 键盘 – 大部分都已就位,但我在使用删除键时遇到问题,更具体地说,在删除整个单词时遇到问题。

问题是 self.textDocumentProxy.documentContextBeforeInput?.isEmpty 返回 Nil,即使文本字段中还有剩余字符也是如此。

这是背景: 如果您不熟悉,它在普通 iOS 键盘上的工作方式是在按住退格键的同时,系统一次删除一个字符(前 10 个字符)。 10 个字符后,它开始删除整个单词。

在我的代码中,我删除了 10 个单个字符,然后成功删除了几个完整的单词,然后突然 self.textDocumentProxy.documentContextBeforeInput?.isEmpty 返回 Nil,即使文本中还有剩余字符字段。

我查看了所有文档和网络,但没有看到其他人遇到同样的问题,所以我确定我遗漏了一些明显的东西,但我感到困惑。

以下是我的类定义的相关部分:

class KeyboardViewController: UIInputViewController { 

//I've removed a bunch of variables that aren't relevant to this question.

    var myInputView : UIInputView {
    return inputView!
}
private var proxy: UITextDocumentProxy {
    return textDocumentProxy
}
override func canBecomeFirstResponder() -> Bool {
    return true
}

override func viewDidLoad() {
    super.viewDidLoad()
    //proxy let proxy = self.textDocumentProxy


    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillAppear"), name: UIKeyboardWillShowNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide"), name: UIKeyboardWillHideNotification, object: nil)


    self.myInputView.translatesAutoresizingMaskIntoConstraints = true

    // Perform custom UI setup here
    view.backgroundColor = UIColor(red: 209 / 255, green: 213 / 255, blue: 219 / 255, alpha: 1)

    NSNotificationCenter.defaultCenter().addObserver(self, selector: "touchUpInsideLetter:", name: "KeyboardKeyPressedNotification", object: nil)

    showQWERTYKeyboard()
}

我为退格按钮设置了监听器和 Action ,因为我还在按钮上配置了一堆其他属性。我在 Switch 中这样做——相关部分在这里:

case "<<":
            isUIButton = true
            normalButton.setTitle(buttonString, forState: UIControlState.Normal)
            normalButton.addTarget(self, action: "turnBackspaceOff", forControlEvents: UIControlEvents.TouchUpInside)
            normalButton.addTarget(self, action: "turnBackspaceOff", forControlEvents: UIControlEvents.TouchUpOutside)
            normalButton.addTarget(self, action: "touchDownBackspace", forControlEvents: UIControlEvents.TouchDown)
            let handleBackspaceRecognizer : UILongPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: "handleBackspaceLongPress:")
            normalButton.addGestureRecognizer(handleBackspaceRecognizer)

            buttonWidth = standardButtonWidth * 1.33
            nextX = nextX + 7

感谢您提供的任何想法。

****修改原始帖子以帮助更清楚地说明问题**** 以下是旨在创建退格行为的 4 个函数。它们似乎至少对前两个完整单词工作正常,但随后正确建议的可选检查开始评估为 nil 并停止删除。

    //Gets called on "Delete Button TouchUpInside" and "Delete Button TouchUpOutside"
func turnBackspaceOff() {

    self.backspaceIsPressed = false
    keyRepeatTimer.invalidate()

}

//Handles a single tap backspace
func touchDownBackspace() {

    (textDocumentProxy as UIKeyInput).deleteBackward()

}

//Handles a long press backspace
func handleBackspaceLongPress(selector : UILongPressGestureRecognizer) {

    if selector.state == UIGestureRecognizerState.Began {
        self.backspaceIsPressed = true
        self.keyRepeatTimer = NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: "backspaceRepeatHandlerFinal", userInfo: nil, repeats: true)
        print("handleBackspaceLongPress.Began")
    }
    else if selector.state == UIGestureRecognizerState.Ended {
        self.backspaceIsPressed = false
        keyRepeatTimer.invalidate()
        numberOfKeyPresses = 0
        print("handleBackspaceLongPress.Ended")
    }
    else {
        self.backspaceIsPressed = false
        keyRepeatTimer.invalidate()
        numberOfKeyPresses = 0
        print("handleBackspaceLongPress. Else")
    }

}

func backspaceRepeatHandlerFinal() {

        if let documentContext = proxy.documentContextBeforeInput as String? {
            print(documentContext)
        }

        print("backspaceRepeatHandlerFinal is called")
        if self.backspaceIsPressed {
            print("backspace is pressed")
            self.numberOfKeyPresses = self.numberOfKeyPresses + 1

            if self.numberOfKeyPresses < 10 {

                    proxy.deleteBackward()

            }
            else {

                if let documentContext = proxy.documentContextBeforeInput as NSString? {
                        let tokens : [String] = documentContext.componentsSeparatedByString(" ")
                        var i : Int = Int()
                    for i = 0; i < String(tokens.last!).characters.count + 1; i++ {
                            (self.textDocumentProxy as UIKeyInput).deleteBackward()
                        }

                }
                else {
                    print("proxy.documentContextBeforeInput was nil")
                    self.keyRepeatTimer.invalidate()
                    self.numberOfKeyPresses = 0
                }
            }
        }
        else {
            print("In the outer else")
            self.keyRepeatTimer.invalidate()
            self.numberOfKeyPresses = 0
        }
}

最后,我不完全明白为什么,但是 XCode 在我创建键盘扩展时自动在下面插入了这两个函数。我对它们进行了轻微修改,以尝试使其正常工作。

    override func textWillChange(textInput: UITextInput?) {
    // The app is about to change the document's contents. Perform any preparation here.
    super.textWillChange(textInput)
}

override func textDidChange(textInput: UITextInput?) {
    // The app has just changed the document's contents, the document context has been updated.

    var textColor: UIColor
    //let proxy = self.textDocumentProxy
    if proxy.keyboardAppearance == UIKeyboardAppearance.Dark {
        textColor = UIColor.whiteColor()
    } else {
        textColor = UIColor.blackColor()
    }
    super.textDidChange(textInput)
}

最佳答案

让我们描述下面这行代码的作用:

if !((self.textDocumentProxy.documentContextBeforeInput?.isEmpty) == nil) {

首先,它需要一个标记为 optional 的对象(由 ? 字母):

let documentContext = self.textDocumentProxy.documentContextBeforeInput

然后,它会尝试读取名为 isEmpty 的属性:

let isEmpty = documentContext?.isEmpty

然后它评估条件:

if !(isEmpty == nil) {

有两个错误。第一个是您将 Bool 值与 nil 进行比较。另一个是您不确定 documentContext 不是 nil

所以,让我们以更合适的方式编写您的代码:

if let documentContext = self.textDocumentProxy.documentContextBeforeInput { // Make sure that it isn't nil
    if documentContext.isEmpty == false { // I guess you need false?
        // Do what you want with non-empty document context
    }
}

关于iOS 键盘 : textDocumentProxy. documentContextBeforeInput.isEmpty 意外返回 Nil(当它不应该返回时),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34536521/

相关文章:

iphone - 调用方式 - (CGFloat)tableView :(UITableView *)tableView heightForFooterInSection:(NSInteger)section without reloading

iphone - 使用 NSDictionary 'initWithContentsOfURL' 代替 Reachability.h

swift - 如何在 Swift 中尊重 MVC?

ios - isRegisteredForRemoteNotifications 即使注册成功也返回 false

ios - 连接到 MySQL 数据库并创建数组以在其他地方使用 Swift

android - 从自定义键盘复制/粘贴剪贴板

ios - 使用 GCM 在 IO 中实现推送通知

ios - 多个命令在存档上产生 gRPCCertificates.bundle 错误(iOS Xcode 11.1,Firebase SDK)

ios - 为 iOS 键盘创建自定义表情符号

ios - 检查自定义键盘中 documentContextBeforeInput 中的字符