NSTextView textDidChange 未通过绑定调用

NSTextView textDidChange not called through binding

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

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

编辑文本时,我会更新

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

...作为 NSTextView 的委托。

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

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

如果不是,这是一个错误或设计使然,我是否应该只观察并手动更新值并通过自己的委托方法调用?失去绑定的优雅似乎是一种耻辱。

请注意,这个问题之前已经被问过,但如果没有被标记为正确回答:NSTextView textDidChange/didChangeText not called for bindings

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

didChangeText 是绑定更新的 source。如果您重写它并且不调用 super,绑定就会被破坏。 didChangeText 调用委托方法 textDidChange.

不幸的是,在布局和存储委托调用之后,didChangeText 在 NSTextView 更新过程中也被调用得相当晚。

这让我感到沮丧,因为我需要在调用我的委托之前更改模型 - 我正在使用另一个视图开始单独计算 NSTableView 行高。如果这些是在模型更新之前完成的,我得到的高度是错误的。

我发现无法区分 NSTextView 代码中对字符串的模型和文本视图更新。我在 didProcessEditing 中捕获了 all 字符串更新作为 NSTextStorage 委托。

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 在这些委托调用之后的某个时间被调用。因此,我不得不凑合让文本视图初始化更改调用我的委托两次。它效率低下,但我找不到过滤掉它的方法。