Обновление содержимого нескольких объектов NSTextView за одну операцию - PullRequest
0 голосов
/ 30 мая 2018

Приложение базы данных, над которым я работаю, может иметь окно с несколькими элементами NSTextView для отображения и редактирования данных.Когда текущее место в базе данных перемещается, все объекты NSTextView в окне должны быть обновлены с новым содержанием.Это делается с помощью цикла, который сканирует каждый объект и проверяет, нужно ли его обновить.Если это так, вычисляется новое значение, а затем обновляется с использованием метода [NSTextView setString:].Вот упрощенная версия задействованного кода.

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

Это работает, но если объектов много, он несколько медленный.Возможно, это связано с тем, что дисплей обновляется не все сразу, вы можете увидеть «рябь» при обновлении объектов, как показано в этом фильме (этот фильм был замедлен до 1/4 скорости, чтобы сделать эффект ряби более выраженным, но это определенно видно на полной скорости).

enter image description here

Если вы продвинулись так далеко, вы можете заподозрить, что метод calcValue медленный,но это не проблема.В других местах используется тот же код и выполняется с десятками тысяч операций в секунду.Кроме того, эта задержка возникает только во время операций обновления, она не возникает при первом открытии окна, даже если в это время требуются те же вычисления.Вот пример.Обратите внимание, что когда я переключаюсь обратно в подробный вид, все объекты NSTextView обновляются мгновенно, даже если запись изменилась и все значения отличаются.

enter image description here

Я подозреваю, что метод [NSTextView setString:] обновляет внеэкранный буфер, а затем немедленно копирует его в экранный буфер, так что двойная буферизация происходит снова и снова для каждого элемента, вызывая задержку и пульсацию.Если так, я уверен, что должен быть какой-то способ предотвратить это, чтобы экран обновлялся только в конце после того, как все значения были обновлены.Возможно, это что-то простое, что мне не хватает, но я боюсь, что я озадачен тем, как это должно быть сделано.

Кстати, это приложение не использует представления на основе слоев и несвязаны с каркасом QuartzCore.

1 Ответ

0 голосов
/ 20 июня 2018

Я поднял этот вопрос с инженерами Apple в лабораториях WWDC 2018.Оказывается, проблема в том, что метод setString: не помечает объект NSTextView как необходимый для отображения.Система в конечном итоге замечает, что текст изменился, и обновляет отображение, но это происходит в асинхронном процессе, отсюда и эффект «ряби».Таким образом, обходной путь - просто добавить вызов к setNeedsDisplay после вызова setString.

[objectTextView setString: updatedValue]
[objectTextView setNeedsDisplay:YES];

Добавление этой одной строки кода устранило проблему, больше никакого волнового эффекта.

IМне сказали, что это на самом деле ошибка, так что, надеюсь, эта дополнительная строка не понадобится в будущих версиях macOS.По запросу был подан радар (41273611, если это читают инженеры Apple).

...