在单个操作中更新多个 NSTextView 对象的内容

Updating contents of multiple NSTextView objects in a single operation

我正在处理的数据库应用程序可以有一个 window,其中包含多个用于显示和编辑数据的 NSTextView 元素。当数据库中的当前位置被重新定位时,window 中的所有 NSTextView 对象都需要更新为新内容。这是通过一个循环来完成的,该循环扫描每个对象并检查它是否需要更新。如果是,则计算新值,然后使用 [NSTextView setString:] 方法更新。这是所涉及代码的简化版本。

for formObject in formObjectsInWindow {
    NSTextView * objectTextView = [formObject textView];
    NSString * updatedValue = [formObject calculateValue];
    [objectTextView setString: updatedValue];
}

这可行,但如果有很多对象,它会有点慢。可能相关,显示不会立即全部更新,您实际上可以看到 "ripple" 随着对象的更新,如这部电影所示(这部电影已减慢到 1/4 速度以产生涟漪效果更明显,但在全速下绝对可见)。

如果到目前为止,您可能会怀疑 calculateValue 方法很慢,但这不是问题所在。在其他地方使用相同的代码并以每秒数万次操作的速度运行。此外,此延迟仅发生在更新操作期间,首次打开 window 时不会发生,即使此时需要进行相同的计算。这是一个例子。请注意,当我切换回详细视图时,所有 NSTextView 对象都会立即更新,即使记录已更改并且所有值都不同。

我怀疑 [NSTextView setString:] 方法正在更新屏幕外缓冲区,然后立即将其复制到屏幕上缓冲区,因此这种双缓冲对每个项目一遍又一遍地发生,造成延迟和纹波。如果是这样,我确定必须有某种方法来防止这种情况发生,以便屏幕仅在所有值都已更新后才在最后更新。这可能是我遗漏的一些简单的事情,但恐怕我对如何完成这件事感到困惑。

顺便说一句,这个应用程序不使用层支持视图,也没有链接到 QuartzCore 框架。

我在 WWDC 2018 实验室向 Apple 工程师提出了这个问题。结果发现问题是 setString: 方法没有将 NSTextView 对象标记为需要显示。系统最终会注意到文本已更改并更新显示,但这是在异步过程中发生的,因此会产生 "ripple" 效果。所以解决方法就是在调用 setString.

之后添加对 setNeedsDisplay 的调用
[objectTextView setString: updatedValue]
[objectTextView setNeedsDisplay:YES];

添加这一行代码解决了问题,不再有连锁反应。

有人告诉我这实际上是一个错误,所以希望在未来的 macOS 版本中不需要这一行。根据要求,已提交雷达(如果有任何 Apple 工程师正在阅读此内容,则为 41273611)。