Чтобы прояснить цель этого вопроса: Я знаю, КАК создавать сложные представления как с вложенными представлениями, так и с использованием drawRect. Я пытаюсь полностью понять, когда и почему следует использовать одно, а не другое. Я также понимаю, что не имеет смысла оптимизировать так много заранее, и делать что-то более сложным способом, прежде чем делать профилирование. Считайте, что мне удобно работать с обоими методами, и теперь я действительно хочу более глубокого понимания. Большая часть моего замешательства связана с изучением того, как сделать прокрутку представления таблицы действительно плавной и быстрой. Конечно, первоисточник этого метода принадлежит автору twitter для iPhone (ранее tweetie). В основном здесь говорится, что для плавной прокрутки таблицы секрет в том, чтобы НЕ использовать вложенные представления, а вместо этого делать всю отрисовку в одном пользовательском uiview. По сути, кажется, что использование большого количества вложенных представлений замедляет рендеринг, потому что они имеют много накладных расходов и постоянно перекомпонуются поверх своих родительских представлений. Справедливости ради стоит отметить, что это было написано, когда 3GS был совсем новым, и с тех пор iDevices стали намного быстрее. Тем не менее этот метод регулярно предлагается в Интернете и в других местах для высокопроизводительных таблиц. На самом деле этот метод предлагается в Apple's Table Sample Code, он был предложен в нескольких видео WWDC (Practical Drawing for iOS Developers) и во многих книгах по iOS программированию. Существуют даже потрясающие инструменты для создания графики и генерации кода Core Graphics для нее. Так что сначала мне кажется, что "есть причина, по которой существует Core Graphics. Она быстрая! ". Но как только я думаю, что понял идею "Предпочитать Core Graphics, когда это возможно", я начинаю видеть, что drawRect часто ответственен за плохую отзывчивость в приложении, чрезвычайно дорог по памяти и действительно нагружает CPU. По сути, я должен "избегать переопределения drawRect" (WWDC 2012 iOS App Performance: Graphics and Animations). Так что я думаю, как и все, это сложно. Может быть, вы поможете мне и другим понять, когда и зачем использовать drawRect? Я вижу пару очевидных ситуаций для использования Core Graphics:
Спасибо всем за информацию. Некоторые уточняющие вопросы здесь:
Придерживайтесь UIKit и вложенных представлений, когда это возможно. Вы можете быть более продуктивными и использовать все механизмы OO, которые облегчают поддержку. Используйте Core Graphics, когда вы не можете добиться нужной производительности от UIKit, или знаете, что попытка собрать эффекты рисования в UIKit будет более сложной.
Общий рабочий процесс должен заключаться в построении табличных представлений с вложенными представлениями. Используйте Instruments для измерения частоты кадров на самом старом оборудовании, которое будет поддерживать ваше приложение. Если вы не можете получить 60 кадров в секунду, опуститесь до CoreGraphics. Когда вы проделаете это некоторое время, вы поймете, когда UIKit, вероятно, является пустой тратой времени.
Итак, почему Core Graphics работает быстро?
CoreGraphics на самом деле не очень быстрый. Если он используется постоянно, то вы, вероятно, работаете медленно. Это богатый API рисования, который требует, чтобы его работа выполнялась на CPU, в отличие от многих работ UIKit, которые перекладываются на GPU. Если бы вам нужно было анимировать мяч, движущийся по экрану, было бы ужасной идеей вызывать setNeedsDisplay для представления 60 раз в секунду. Поэтому, если у вас есть подкомпоненты представления, которые должны быть анимированы по отдельности, каждый компонент должен быть отдельным слоем.
Другая проблема заключается в том, что если вы не делаете пользовательскую отрисовку с помощью drawRect, UIKit может оптимизировать стоковые представления таким образом, что drawRect будет не нужен, или же он может использовать короткие пути при композитинге. Когда вы переопределяете drawRect, UIKit вынужден идти медленным путем, потому что он понятия не имеет, что вы делаете.
Эти две проблемы могут быть перевешены преимуществами в случае с ячейками табличного представления. После вызова drawRect, когда представление впервые появляется на экране, его содержимое кэшируется, и прокрутка представляет собой простой перевод, выполняемый GPU. Поскольку вы имеете дело с одним представлением, а не со сложной иерархией, оптимизация drawRect в UIKit' становится менее важной. Таким образом, узким местом становится то, насколько вы можете оптимизировать отрисовку в Core Graphics.
Всегда, когда это возможно, используйте UIKit. Делайте самую простую реализацию, которая работает. Профиль. Когда есть стимул, оптимизируйте.
Разница в том, что ему UIView и CALayer, главным образом в неподвижных изображений. Эти снимки загружаются в видеокарту (если вы знаете OpenGL, не думаю, что изображения в качестве текстуры и в UIView/CALayer как многоугольник, показывающий такую текстуру). После выбора изображения на GPU, он может быть очень быстро оформили, и даже несколько раз, и (с небольшое уменьшение производительности) даже с различными уровнями Альфа-прозрачность поверх других изображений.
CoreGraphics/кварц API для генерация изображения. Он принимает буфер пикселей (опять же, думаю, текстуру OpenGL) и изменяет отдельные пиксели внутри него. Все это происходит в оперативной памяти и на процессоре, и только после кварца делается, делает изображения приобретают "промыть" и обратно в ГПУ. Этот раунд-трип получения изображения от GPU, изменять его, то загрузки всего изображения (или, по крайней мере сравнительно большой кусок) обратно в ГПУ довольно медленно. Также, рисование, что кварц делает, а очень быстро за то, что вы делаете, намного медленнее, чем то, что ГПУ делает.
Что's очевидным, учитывая графического процессора в основном передвигаться без изменений пикселей в большие куски. Кварц делает произвольным доступом пикселей и делит процессор с сетевые, аудио и т. д. Также, если у вас есть несколько элементов, которые вы рисуете, используя кварцевые в то же время, вам придется заново рисовать все из них, когда один изменяет, а затем загрузить весь кусок, а если вы изменяете одно изображение, а затем пусть UIViews или CALayers вставить его на другие изображения, вы можете уйти с загружать гораздо меньше данных для GPU.
Когда вы Don'т реализовать -drawRect:, большинство мнений может быть оптимизирован подальше. Они Дон'т содержать никаких пикселей, так что может'т сделать что угодно. Другими представлениями, как помощью UIImageView, только нарисовать объектами UIImage (что, опять же, по сути, ссылка на текстуру, которая, очевидно, уже загружен на ГПУ). Так что если вы рисуете то же объектами UIImage 5 раз с помощью помощью UIImageView, он загружен только на ГПУ один раз, а потом тянет на дисплей в 5 разных местах, экономя нам время и процессора.
Когда вы реализуете -drawRect:, это вызывает новый образ будет создан. Затем вы рисуете в том, что на CPU с использованием кварца. Если вы рисуете объектами UIImage в вашем drawRect, он, вероятно, загружает изображения из ГПУ, копирует его в изображение, которое вы'ре рисунок, и как только вы'повторно сделано, загружает этот копия изображение обратно в видеокарту. Так что вы're через два GPU памяти на устройстве.
Так что самый быстрый способ привлечь обычно, чтобы сохранить статический контент отделен от изменения содержания (в отдельных UIViews/наследник UIView подклассы/CALayers). Статическая нагрузка контент как объектами UIImage и нарисовать его с помощью помощью UIImageView и контента динамически создаются во время выполнения в drawRect. Если у вас есть контент, который неоднократно обращается, но сам по себе не'т изменение (т. е. 3 иконки, которые показывают в тот же слот, чтобы указать на определенный статус) пользоваться помощью UIImageView, а также.
Один нюанс: есть такая вещь, как слишком много UIViews. Особенно прозрачные участки занять больше пошлины на GPU рисовать, потому что они должны быть смешаны с другими пикселями за ними при отображении. Именно поэтому вы можете отметить в UIView как "непрозрачно" и указать в ГПУ, что он может просто уничтожить все за этот образ.
Если у вас есть контент, который создается динамически во время выполнения, но остается одинаковым в течение всего срока применения'ы жизни (например, метки, содержащие имя пользователя) это на самом деле может имеет смысл просто рисовать все это дело сразу через кварц, с текстом, кнопка границы и т. д., как часть фона. Но, что'ы, как правило, оптимизация, что'не нужно, только если приложение инструментов говорит вам, иначе.
Я постараюсь вести здесь краткое изложение того, что я экстраполирую из ответов других людей, и задавать уточняющие вопросы в обновлении первоначального вопроса. Но я призываю других продолжать отвечать на вопросы и голосовать за тех, кто предоставил хорошую информацию.
Совершенно ясно, что общий подход, как отметил Бен Сандофски в своем ответе, должен быть "Всегда, когда вы можете, используйте UIKit. Делайте самую простую реализацию, которая работает. Профиль. Когда есть стимул, оптимизируйте.".
Отрисовка содержимого ячеек в одном плоском UIView может значительно улучшить FPS при прокрутке таблиц..
Как я уже сказал выше, CPU и GPU - это два возможных узких места. Поскольку они обычно обрабатывают разные вещи, вы должны обратить внимание на то, с каким узким местом вы сталкиваетесь. В случае с прокруткой таблиц дело не в том, что Core Graphics рисует быстрее, и именно поэтому он может значительно улучшить ваш FPS..
На самом деле, Core Graphics вполне может быть медленнее, чем вложенная иерархия UIView для начального рендеринга. Однако, похоже, что типичная причина нестабильной прокрутки - это узкое место на GPU, поэтому вам нужно решить эту проблему.
Почему переопределение drawRect (с использованием графического ядра) может помочь прокрутке таблицы:.
Насколько я понимаю, GPU не отвечает за первоначальный рендеринг представлений, вместо этого ему передаются текстуры или растровые изображения, иногда с некоторыми свойствами слоя, после того, как они были отрендерены. Затем он отвечает за компоновку растровых изображений, рендеринг всех этих свойств слоев и большую часть анимации (Core Animation).
В случае с ячейками табличного представления GPU может быть узким местом при сложной иерархии представлений, потому что вместо анимации одного растрового изображения он анимирует родительское представление, выполняет расчеты расположения вложенных представлений, рендеринг эффектов слоев и композицию всех вложенных представлений. Таким образом, вместо анимации одного растрового изображения, он отвечает за взаимосвязь множества растровых изображений и их взаимодействие для одной и той же области пикселей.
Подводя итог, причина, по которой рисование ячейки в одном представлении с графическим ядром может ускорить прокрутку таблицы, заключается НЕ в том, что оно рисует быстрее, а в том, что оно снижает нагрузку на GPU, который является узким местом, создающим проблемы в данном конкретном сценарии.
Я разработчик игр, и я задавал те же вопросы, когда мой друг сказал мне, что моя иерархия представлений на основе UIImageView замедлит мою игру и сделает ее ужасной. После этого я начал исследовать все, что мог найти о том, следует ли использовать UIViews, CoreGraphics, OpenGL или что-то стороннее, например Cocos2D. Последовательный ответ, который я получил от друзей, учителей и инженеров Apple на WWDC, заключался в том, что в конечном итоге не будет большой разницы, потому что на каком-то уровне все они делают одно и то же. Опции более высокого уровня, такие как UIViews, опираются на опции более низкого уровня, такие как CoreGraphics и OpenGL, просто они обернуты в код, чтобы вам было проще их использовать.
Не используйте CoreGraphics, если вы собираетесь в конечном итоге просто переписать UIView. Однако, вы можете получить некоторую скорость от использования CoreGraphics, если вы делаете все свои рисунки в одном представлении, но действительно ли это того стоит? Ответ, который я нашел, обычно отрицательный. Когда я только начинал свою игру, я работал с iPhone 3G. По мере усложнения игры я начал замечать некоторые задержки, но на новых устройствах они были совершенно незаметны. Теперь у меня происходит много действий, и единственным отставанием кажется падение на 1-3 fps при игре на самом сложном уровне на iPhone 4.
И все же я решил использовать Instruments, чтобы найти функции, которые отнимают больше всего времени. Я обнаружил, что проблемы не связаны с использованием UIViews. Вместо этого он неоднократно вызывал CGRectMake для определенных расчетов определения столкновений, а также загружал изображения и аудиофайлы отдельно для некоторых классов, использующих одни и те же изображения, вместо того, чтобы заставить их черпать из одного центрального класса хранения.
Так что, в конце концов, вы можете получить небольшой выигрыш от использования CoreGraphics, но обычно это того не стоит или может вообще не иметь никакого эффекта. Единственный раз, когда я использую CoreGraphics, это при рисовании геометрических фигур, а не текста и изображений.