未通过绑定调用NSTextView textDidChange

时间:2019-02-07 13:06:25

标签: cocoa appkit nstextview

我有NSTextViews,需要在其中跟踪文本的当前端点以放置界面元素。

我将模型字符串绑定到文本视图上的NSBindingName.value。

在编辑文本后,我会在

中更新界面元素的位置
func textDidChange(_ notification: Notification)

...作为NSTextView的委托。

但是,如果我的模型是字符串更新的源,则即使在NSTextView中正确更新了文本,也不会调用此委托方法。

所以,我做错什么了吗,绑定的更改应该调用textDidChange吗?

如果不是,并且这是一个错误或特意设计,我是否应该观察并手动更新值并通过自己的委托方法进行调用?失去绑定的优雅似乎很可惜。

请注意,之前曾有人问过此问题,但如果不是NSTextView textDidChange/didChangeText not called for bindings

,则将其标记为正确答案

1 个答案:

答案 0 :(得分:0)

当绑定更新文本(而不是文本视图更新模型)时,调用NSTextView方法didChangeText。

didChangeText是绑定更新的。如果您覆盖它并且不调用super,则绑定会中断。 didChangeText调用委托方法textDidChange。

不幸的是,在NSTextView更新过程的后期(在布局和存储委托调用之后),didChangeText也被调用。

这让我感到沮丧,因为在我打电话给代表之前,我需要更改模型-我正在用另一个视图对NSTableView行高进行单独的计算。如果这些是在模型更新之前完成的,那么我的高度会错误。

我发现无法从NSTextView代码中区分字符串的模型更新和textview更新。我以NSTextStorage委托的形式在didProcessEditing中捕获了对字符串的所有更新。

func textStorage(_ textStorage: NSTextStorage,
                 didProcessEditing editedMask: NSTextStorageEditActions,
                 range editedRange: NSRange,
                 changeInLength delta: Int)
{
    if editedMask.contains(.editedCharacters) {
        textStringDidChange = true
    }
}

我只是在这里设置了一个标志,因为如果他们尝试以任何方式更新NSTextView,对我的委托的调用都会崩溃。然后,我在以下NSLayoutManagerDelegate调用中使用了此标志:

func layoutManagerDidInvalidateLayout(_ sender: NSLayoutManager)
    {
        if textStringDidChange {
            delegate?.textDidChange?(Notification(name: .init("")))
            textStringDidChange = false
        }
    }
在这些委托调用之后的某个时间调用

didChangeText。因此,我不得不处理文本视图初始化的更改,两次调用我的代表。它效率低下,但我找不到将其过滤掉的方法。