Повторяя NSTimer блокирует поток пользовательского интерфейса - PullRequest
1 голос
/ 14 июля 2011

Прежде всего, я знаю, что есть несколько других вопросов StackOverflow по этой теме, но я прочитал их все, и я все еще не понимаю, что делать в моей ситуации. Я, наверное, упускаю что-то очевидное здесь, если бы вы могли помочь прояснить это, будет очень признателен!

У меня есть приложение, которое выполняет большую работу по анимированию изображений в представлении, в основном состоящее из нескольких изображений, движущихся по прямой линии в течение одной или двух секунд за один раз. Сначала я решил сделать их простыми, отключив анимацию, используя UIView animateWithDuration на все время движения. Но я обнаружил, что это не дает мне много сил, чтобы перехватить движение, остановить его или проверить, где оно было, поэтому я отказался от него. Мой новый подход состоит в том, чтобы использовать NSTimer, стреляя 20 раз в секунду, делая дополнительные движения. Таким образом, я также могу вмешаться (почти) мгновенно, чтобы изменить анимацию, остановить ее или обновить метку состояния в зависимости от того, как далеко она прошла, и т. Д., И т. Д.

Прежде всего ... возможно, есть лучший способ, чем этот. Не стесняйтесь предложить что-то лучшее!

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

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

Какие у меня есть варианты? Сначала я подумал, что мог бы создать новую тему, чтобы запустить таймер. Но я помню, что читал, что обновления пользовательского интерфейса в любом случае должны происходить в основном потоке. Почему это? И плюс, это действительно решило бы проблему? Я просто прошу слишком много устройства для обработки этого таймера, а также взаимодействия пользовательского интерфейса? Что-то еще мне не хватает?

Буду признателен за любой совет.

Edit:

Я только что нашел причину моей проблемы блокировки пользовательского интерфейса. Я использовал animateWithDuration с блоками, но не устанавливал параметры. Поэтому UIViewAnimationOptionAllowUserInteraction не было установлено. Я изменил его, чтобы установить эту опцию, и мой пользовательский интерфейс теперь радостно реагирует.

Тем не менее, я все равно оставлю этот вопрос открытым для конкретных предложений относительно моего общего подхода. Спасибо.

Ответы [ 3 ]

0 голосов
/ 14 июля 2011

Я думаю, вы обнаружите, что даже если вы оптимизируете это, анимация на основе таймера не будет работать хорошо.

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

0 голосов
/ 05 августа 2011

Я хотел бы рассмотреть вопрос об использовании CADisplayLink.Из документации:

Объект CADisplayLink - это объект таймера, который позволяет вашему приложению синхронизировать чертеж с частотой обновления экрана.

Ваше приложение создает новую ссылку на отображение, предоставляя цельобъект и селектор для вызова при обновлении экрана.Затем ваше приложение добавляет ссылку на отображение в цикл выполнения.

Как только ссылка на отображение связана с циклом выполнения, селектор на цели вызывается, когда необходимо обновить содержимое экрана.Цель может прочитать свойство временной метки отображаемой ссылки, чтобы получить время, когда был отображен предыдущий кадр.Например, приложение, которое отображает фильмы, может использовать метку времени, чтобы вычислить, какой видеокадр будет отображаться следующим.Приложение, которое выполняет свои собственные анимации, может использовать метку времени, чтобы определить, где и как отображаются объекты в следующем кадре.Свойство duration указывает количество времени между кадрами.Вы можете использовать это значение в своем приложении для расчета частоты кадров дисплея, приблизительного времени, в течение которого будет отображаться следующий кадр, и для настройки поведения при рисовании так, чтобы следующий кадр был подготовлен вовремя для отображения.

Ваше приложение может отключить уведомления, установив для свойства paused значение YES.Кроме того, если ваше приложение не может предоставить кадры в указанное время, вы можете выбрать более медленную частоту кадров.Приложение с более медленной, но постоянной частотой кадров кажется пользователю более плавным, чем приложение, пропускающее кадры.Вы можете увеличить время между кадрами (и уменьшить видимую частоту кадров), изменив свойство frameInterval.

Когда ваше приложение завершает работу с отображаемой ссылкой, оно должно вызвать invalidate, чтобы удалить ее из всех циклов выполнения и разъединитьэто от цели.

CADisplayLink не должен быть разделен на подклассы.

0 голосов
/ 14 июля 2011

Я не совсем уверен, как все обрабатывается в вашей программе, но вы можете просто рассмотреть возможность использования одного потока / таймера, который контролирует все объекты и их движения.На самом деле нет необходимости создавать отдельный поток / таймер для каждого отдельного объекта, поскольку это легко вызовет проблемы.

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

...