2012-06-19 2 views
0

У меня есть пользовательский вид (унаследованный от UIView) в моем приложении. Пользовательский вид переопределяетCGContextDrawLayerAtPoint работает медленно на iPad 3

- (void) drawRect:(CGRect) rect

Проблема заключается в следующем: drawRect: выполняется во много раз длиннее на IPAD 3, чем на IPAD 2 (приблизительно 0,1 секунды на IPAD 3 и 0,003 секунды на IPad 2). Это примерно в 30 раз медленнее.

В принципе, я использую некоторые предварительно созданные слои и рисую их в drawRect:. Последний звонок

CGContextDrawLayerAtPoint(context, CGPointZero, m_currentLayer); 

занимает большую часть времени (около 95% от общего времени в drawRect:)

Что может быть замедляя вещи так много, и как я должен исправить причину?

UPDATE:

Там нет ни одной темы, непосредственно участвующих. Я вызываю setNeedsDisplay: в одном потоке, и drawRect: получает вызов от другого, но это все. То же самое касается замков (не используются замки).

Представление перерисовывается в ответ на касания (это приложение для раскраски). На iPad 2 я получаю разумную задержку между касанием и обновлением экрана. Я хочу добиться того же на iPad 3.

+0

Только предположение, но, возможно, тот факт, что ваши пиксели вдруг в четыре раза суммы есть что-то делать с ним (отображение сетчатки и все). – borrrden

+0

@borrrden Я думаю, что вы правы, и на iPad 3 должно быть много работы, но весь процесс стал примерно в 30 раз медленнее. – Bobrovsky

+0

Я не думаю, что кто-то может рисковать разумной догадкой только с этой информацией. Является ли какая-то часть этого использования несколькими потоками? Замки Mutex? И почему это проблема для вас? Часто ли просматривается ваш просмотр? Если да, то почему?DrawLayerAtPoint, вероятно, всегда будет самой тяжелой функцией (он также в моем приложении, хотя я использую iPad 2, поэтому я не могу ручаться за его скорость на третьем гене). – borrrden

ответ

7

Итак, iPad 3 определенно медленнее во многих областях. У меня есть теория об этом. Marco Arment noted, что метод renderInContext смехотворно медленный на новом iPad. Я также обнаружил, что это происходит при попытке создать увеличительное стекло для пользовательского текстового представления. В конце концов мне пришлось отказаться от renderInContext для пользовательского графического графического графика.

У меня также возникла проблема с ошибками wait_fences на моей основной графике: Only on new iPad 3: wait_fences: failed to receive reply: 10004003.

Это то, что я догадался до сих пор. IPad 3, очевидно, имеет в 4 раза больше пикселей. Это может вызвать проблемы в двух местах:

  1. Во-первых, центральный процессор. Все основные графические чертежи выполняются процессором. В случае ротационных событий, если процессор занимает слишком много времени, он обращается к ошибке wait_fences, которая, по моему мнению, является просто вызовом, который говорит устройству подождать немного дольше, чтобы фактически выполнить поворот, а значит, и задержку.
  2. Перенос изображений на GPU. Графический процессор, очевидно, отлично справляется с разрешением сетчатки (см. Infinity Blade 2). Но при рисовании основной графики он обращает свои изображения непосредственно в буферы GPU, чтобы избежать memcpy. Тем не менее, либо буферы GPU не изменились с iPad 2, либо просто не сделали их достаточно большими, потому что очень просто перегрузить эти буферы. Когда это произойдет, я считаю, что процессор записывает изображения в стандартную память , а затем копирует их на GPU, когда буферы GPU могут обрабатывать его. Это, я думаю, вызывает проблемы с производительностью. Эта дополнительная копия занимает много времени с таким количеством пикселей и значительно замедляет работу.

Чтобы избежать тетсру я рекомендую несколько вещей:

  1. только сделать то, что вам нужно.Избегайте рисовать что-либо за кадром любой ценой. Если вы рисуете большой вид, но только отображаете часть этого представления (например, подкрытия, охватывающие его), попытайтесь найти способ рисовать только то, что видно.
  2. Если вам нужно нарисовать большой вид, подумайте о том, чтобы разбить вид на части либо в виде подзонов, либо подслоев (возможно, подслоев в вашем случае). И только перерисуйте то, что вам нужно. Например, возьмите приложение для заметки. Когда вы увеличиваете масштаб, вы можете буквально наблюдать за его перерисованием по одному квадрату за раз. Или в сафари вы можете наблюдать за обновлением квадратов при прокрутке. К сожалению, мне не приходилось это делать, поэтому я не уверен в методологии.
  3. Постарайтесь, чтобы ваши рисунки были просты. У меня было удивительное выглядящее текстовое представление основного текста, которое пришлось перерисовывать на каждом введенном символе. Очень медленно. Я изменил фон на простой белый (в основной графике), и он ускорился. Еще лучше было бы для меня не перерисовывать фон.

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

UPDATE

Так компании Apple теперь выпустил в 2012 году WWDC Developer видео. У них есть два видео, которые могут помочь вам (требуется аккаунт разработчика):

  1. iOS App Performance: Responsiveness
  2. iOS App Performance: Graphics and Animation

Одна вещь, которую они говорят о я думаю, что может помочь вам в использовании метода: setNeedsDisplayInRect:(CGRect)rect. Используя этот метод вместо обычного setNeedsDisplay и следя за тем, чтобы ваш метод drawRect только рисовал прямоугольник, данный ему может значительно помочь производительности. Лично я использую функцию: CGContextClipToRect(context, rect);, чтобы кликнуть мой рисунок только на прямоугольник.

В качестве примера у меня есть отдельный класс, который я использую для непосредственного рисования текста в своих представлениях с использованием основного текста. Мой подкласс UIView сохраняет ссылку на этот объект и использует его для рисования его текста, а не для использования UILabel. Я использовал, чтобы обновить весь вид (setNeedsDisplay), когда текст изменится. Теперь у меня есть объект CoreText, который вычисляет измененный CGRect и использует setNeedsDisplayInRect только для изменения части представления, содержащей текст. Это действительно помогло моей работе при прокрутке.

+0

Спасибо за ваш ответ. Я думаю, что это ценная информация, хотя я использовал другой источник консультаций в моем случае. – Bobrovsky

1

В итоге я использовал подход, описанный в @ Kurt Revis answer for similar question.

Сведено к минимуму количество используемых слоев, добавлено UIImageView и установите его изображение на UIImage, обертывая мой CGImageRef. Пожалуйста, прочитайте упомянутый ответ, чтобы получить более подробную информацию об этом подходе.

В конце концов мое приложение стало еще проще, чем раньше, и работает почти с одинаковой скоростью на IPad 2 и IPad 3.

Смежные вопросы