NSTextView замораживает мое приложение при асинхронном добавлении большого количества данных

Я создаю простое приложение говорящего/слушающего, которое получает данные OSC через UDP. Я использую модуль OSCKit, который сам использует библиотеку CocoaAsyncSocket для внутренней связи UDP. Когда я прослушиваю определенный порт для получения данных от другого программного обеспечения, поддерживающего OSC, я регистрирую полученные команды в файле NSTextView. Проблема в том, что иногда я получаю тысячи сообщений за очень короткий промежуток времени (EDIT: я просто добавил счетчик, чтобы увидеть, сколько сообщений я получаю. Я получил более 14000 всего за несколько секунд, и это это всего лишь один движущийся объект в моей программе). Невозможно предсказать, когда это произойдет, поэтому я не могу заблокировать объект textStorage объекта NSTextView, чтобы он не отправлял все свои уведомления для обновления пользовательского интерфейса. Данные обрабатываются с помощью функции обратного вызова делегата.
Так как же обойти это ограничение?

   ///Handle incoming OSC messages
   func handle(_ message: OSCMessage!) {

      print("OSC Message: \(message)")

      let targetPath = message.address
      let args = message.arguments

      let msgAsString = "Path: \"\(targetPath)\"\nArguments: \n\(args)\n\n"
      print(msgAsString)
      oscLogView.string?.append(msgAsString)
      oscLogView.scrollToEndOfDocument(self)
   }

Как вы можете видеть здесь (это функция обратного вызова), я обновляю TextView непосредственно из обратного вызова (как добавляя данные, так и прокручивая до конца) каждый раз, когда получено сообщение. Именно здесь Инструменты говорят мне, что происходит замедление, и добавление является самым медленным. Я не пошел дальше этого в анализе, но это, безусловно, связано с тем, что он пытается сделать визуальное обновление, которое занимает намного больше времени, чем разбор 32-битных данных, и когда он закончен, он получает еще одно обновление прямо подальше от буфера сервера.

Могу ли я отправить этот вызов в фоновый поток? Мне не кажется хорошей идеей заполнять фоновую ветку визуальными обновлениями. Может быть, увеличить свой собственный строковый буфер и время от времени сбрасывать его в TextView с помощью таймера?

Я хочу придать этому ощущение консоли, но консоль, которая зависает, — это не консоль.

Вот ссылка на проект на github. все стручки уже есть и настроены с помощью кокоаподов, так что просто откройте рабочее пространство. У вас, ребята, может не быть ничего, чтобы генерировать столько OSC-трафика, но если вы действительно хотите покопаться, вы можете получить IanniX, который представляет собой секвенсор/автомат траектории с открытым исходным кодом, который может генерировать OSC и многое другое. Я только что скачал его, и я создам быстрый проект, который должен отправить достаточно данных, чтобы заморозить приложение, и я добавлю его в репозиторий, если кто-то захочет попробовать.


person BadgerBadger    schedule 24.07.2017    source источник
comment
Поскольку у вас есть 14000 результатов, и это было бы неприемлемо в одном интерфейсе прокрутки, не могли бы вы пропустить сообщения, которые приходят примерно через 0,01 с или около того? Таким образом, вы бы блокировали обновление каждые 0,01 с и ждали следующего сообщения после этого, это привело бы к максимуму 100 сообщений в секунду, что было бы достаточно быстро, чтобы увидеть и не замедлить все это, я думаю.   -  person George    schedule 26.07.2017
comment
Ни одно сообщение нельзя пропустить. Я просто заполняю буфер и вместо этого добавляю его в textView с помощью таймера. Работает отлично.   -  person BadgerBadger    schedule 26.07.2017


Ответы (1)


Я добавляю входящие данные в переменную буфера и использую таймер, который сбрасывает этот буфер в текстовое представление каждые 0,2 секунды. Цикл обновления текстового представления слишком медленный, чтобы обрабатывать объем входящих данных, поэтому сброс сетевого обратного вызова на таймер позволяет серверу обрабатывать данные, а не останавливаться каждые 32 бита.

Если кто-нибудь придумает более элегантный метод, я не предубежден.

person BadgerBadger    schedule 24.07.2017
comment
Привет, Барсук. Пожалуйста, отредактируйте свой вопрос, чтобы добавить дополнительную информацию вместо публикации ответа, это делает понимание более ясным. Спасибо. - person George; 26.07.2017
comment
Я думал, что это будет хорошо, так как это решение, которое я нашел;). Я обновлю вопрос сегодня вечером. - person BadgerBadger; 26.07.2017
comment
Упс, извините за это. Последняя строчка меня смутила, ну да ладно, ты прав - person George; 26.07.2017
comment
Пожалуйста, используйте ссылку редактирования на свой вопрос, чтобы добавить дополнительную информацию. Кнопку Опубликовать ответ следует использовать только для полных ответов на вопрос. – Из обзора - person Arpit; 27.07.2017
comment
@Arpit: если вы правильно прочитали, это решение. Если оставить его открытым для предложений, это не станет вопросом. Я еще не пометил вопрос как отвеченный на случай, если получу другие решения. - person BadgerBadger; 27.07.2017